Подтвердить что ты не робот

Трюк с JavaScript: какое значение имеет foo.x

Я нашел эту проблему в коллекции вопросов интервью GitHub:

var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};

Вопрос: какое значение имеет foo.x?

Ответ - undefined.

Я провел некоторое исследование, и я понимаю, что эта проблема (поправьте меня, если я ошибаюсь):

  • var foo = {n: 1}; объявляет объект foo со свойством n, равным 1.
  • var bar = foo; объявляет объект bar, который ссылается на тот же объект, что и foo.
  • foo.x = foo = {n: 2};, который, я считаю, равен foo.x = (foo = {n: 2});
  • И тогда я получил foo.x равный undefined. Однако значением bar.x является объект {n:2}.

Если bar и foo ссылаются на один и тот же объект, почему bar.x получил значение, а foo.x - undefined? Что на самом деле происходит в foo.x = foo = {n: 2};?

4b9b3361

Ответ 1

foo.x = foo = {n: 2};

определяет, что foo.x относится к свойству x объекта {n: 1}, присваивает {n: 2} - foo и присваивает новое значение foo - {n: 2} - свойству x объекта {n: 1}.

Важно то, что foo, которое foo.x ссылается на значение, определяется до того, как изменяется foo.

См. раздел 11.13.1 спецификации ES5:

  • Пусть lref является результатом оценки LeftHandSideExpression.

  • Пусть rref является результатом вычисления AssignmentExpression.

Оператор присваивания связывает права налево, поэтому вы получаете:

foo.x = (foo = {n: 2})

Левая часть оценивается перед правой стороной.

Ответ 2

foo.x = foo = {n: 2};

Здесь foo ссылается на объект {n: 1} до назначения i.e перед выполнением оператора.

Оператор может быть переписан как foo.x = (foo = {n: 2});

В объектных терминах вышеуказанный оператор может быть переписан как {n: 1}.x = ({n: 1} = {n: 2});

Так как назначение происходит только справа налево. Поэтому здесь нам просто нужно проверить, что foo ссылается на какой объект перед запуском.

При решении R.H.S: foo = {n: 2}; Теперь foo ссылается на {n: 2};

Возвращаясь к проблеме, мы остаемся с:

foo.x = foo;

Теперь foo.x на L.H.S по-прежнему {n: 1}.x, тогда как foo на R.H.S есть {n: 2}.

Итак, после выполнения этого оператора {n: 1} станет {n: 1, x: {n: 2}} с баром, который все еще ссылается на него. Где foo теперь будет ссылаться на {n: 2}.

Итак, при выполнении foo.x дает undefined, поскольку в foo есть только 1 значение, которое является {n: 2}.

Но если вы попытаетесь выполнить bar.x, он даст {n: 2}. Или, если вы просто выполните бар, результат будет

Объект {n: 1, x: Объект}

Ответ 3

Я думал, что добавлю еще одно, что я нашел, полезный способ подумать об этом.

Эти последние назначения переменных эквивалентны записи bar.x = foo = {n:2};, поскольку эти переменные являются просто ссылками на одну и ту же вещь в памяти.

Другими словами, foo и bar являются, во-первых, и ссылками на один и тот же объект, {n:1}. Когда вы используете foo.x =, вы получаете доступ к {n:1} и добавляете к нему свойство x. Это можно сделать с помощью bar или foo, потому что они оба указывают на тот же самый объект в памяти! Это не имеет значения.

Затем, когда вы завершите эту строку, foo.x = foo = {n:2}, вы создаете другой, новый, объект в памяти через синтаксис литерала объекта и устанавливаете foo, чтобы указать на этот объект {n:2} вместо того, что сейчас {n:1, x: {n: 2}. Это не влияет на то, что указывает foo, когда вы добавили к нему свойство x.

Это довольно запутанно, но я думаю, что вам кажется, что вы думаете о том, что переменные являются просто указателями на места/объекты в памяти, и этот объектный синтаксис не меняет ранее существовавший объект (хотя они выглядят одинаково), Он создает совершенно новый.

Начало принятого ответа на этот вопрос также может быть полезным.

Ответ 4

Необходимо понимать, что переменные объекта - это просто ссылки на объекты в JavaScript, а не сами объекты.

var foo = {n: 1} → foo ссылается на реальный объект {n: 1} var bar = foo → bar теперь также является ссылкой на реальный объект {n: 1}

Самая сложная часть - это, конечно, третья строка: foo.x = foo = {n: 2}

Это эквивалентно: (reference to {n: 1}).x = (foo = {n: 2}) → после полной оценки этой строки, foo становится ссылкой на новый объект {n: 2}; однако, поскольку foo ссылается на исходный объект {n: 1} до вычисления строки, исходный объект {n: 1} становится {n: 1, x: [reference to]{n: 2}} после линия оценивается, и измененный объект будет доступен через bar ссылок. Если бы не было панели ссылок, исходный объект был бы уничтожен

Ответ 5

Как я понимаю выражение:

foo.x = foo = {n: 2};

точно так же, как:

foo.x = {n: 2} ; 
foo = {n: 2};

И после этого стало очевидно, что:

 bar=={n: 1, x: {n:2}};
 foo=={n:2};
 foo.x==undefined

Ответ 6

я думаю, в Javascript вы не можете присвоить значение свойству, которое не существует, если объект не пуст. так что в этом случае у объекта foo есть пара свойство и значение, которое равно {n: 1}, так как оно не пустое и не имеет свойства ax, вы не можете назначить, но так как вы назначаете объекту bar значение, которое является объектом foo, это будет иметь значение, независимо от того, что это за foo