Трюк с 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};
?
Ответы
Ответ 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:
Оператор присваивания связывает права налево, поэтому вы получаете:
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