Почему значение foo.x undefined в foo.x = foo = {n: 2}?
Этот код:
var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};
Не могли бы вы объяснить, что имеется в виду:
foo.x = foo = {n: 2};
Я вижу, что {n:2}
присваивается foo
. Почему undefined
назначен foo.x
? Возвращает ли foo = {n: 2};
undefined
?
Ответы
Ответ 1
Согласно спецификации, сначала оценивается левая часть выражения присваивания, хотя оператор имеет приоритет справа налево. Таким образом, выражение foo.x = foo = {n: 2}
, которое совпадает с foo.x = (foo = {n: 2})
, оценивается следующим образом:
- Оцените левое выражение
foo.x
, чтобы получить ссылку, в которой будет присвоено значение правого выражения.
- Оцените правое выражение, чтобы получить значение, которое будет назначено. Правая часть - другое выражение присваивания, поэтому оно оценивается одинаково:
- Оцените
foo
, чтобы определить, где назначить.
- Оцените выражение
{n:2}
, которое создает объект, чтобы определить значение для назначения.
- Назначьте
{n:2}
в foo и верните {n:2}
.
- Назначьте значение, которое выражение с правой стороны оценило (
{n:2}
), на ссылку, которую foo.x
разрешал на шаге 1 ( до foo
, был назначен новый стоимость). То же, что и bar.x
, из-за назначения bar = foo
в строке раньше.
Когда это будет сделано, исходный объект, который bar
по-прежнему является ссылкой, будет иметь свойство x
, которое ссылается на второй созданный объект. foo
также является ссылкой на этот второй объект, поэтому foo === bar.x
.
Ответ 2
Поскольку доступ к ресурсу foo.x
слева оценивается перед правой частью.
Позвольте сделать более понятным, что на самом деле делает ваш код, указав новые имена во временные выражения:
var foo0 = {n: 1};
var foo1 = {n: 2};
foo0.x = foo1;
foo0 = foo1;
console.log(foo0.x);
Следовательно, foo0.x
есть foo1.x
is undefined
.
В исходном коде вы можете видеть, что bar.x
is {n: 2}
, подтверждающий это объяснение.
Ответ 3
В соответствии со спецификацией JavaScript левая сторона всегда оценивается сначала:
12.14.4 Семантика времени выполнения: оценка
AssignmentExpression [In, Yield]: LeftHandSideExpression [? Yield]= AssignmentExpression [? In,? Yield]
Если LeftHandSideExpression не является объектом ObjectLiteral или ArrayLiteral, тогда 1. Пусть lref является результатом оценки LeftHandSideExpression.
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-assignment-operators-runtime-semantics-evaluation
Это можно четко увидеть, если добавить еще одну ссылку на объект foo
:
var ref = {n:1};
var foo = ref;
var bar = foo;
foo.x = foo = {n: 2};
ref.x
существует, потому что foo.x
относится к немодифицированному значению foo
.
Ответ 4
Поскольку вы переназначили foo для объекта с единственным свойством, { n: 2 }
.
В JavaScript выражения вычисляются справа налево. Поэтому, когда вы пытаетесь получить доступ к foo.x
, вы пытаетесь получить значение x
из вновь назначенного значения foo, { n: 2 }
, которое равно undefined
.