Как работает a.x = a = {n: b} в JavaScript?

Это связано с выражением Javascript a = b = c.

Я понимаю, что

foo = foo.x = {n: b}; // console.log(foo) => {n: b}

но

foo.x = foo = {n: b}; // console.log(foo) => {n: b}

Он должен быть равен:

foo = {n: b};
foo.x = foo; // console.log(foo) => {n: b, x:object}

Я что-то пропустил?

Ответы

Ответ 1

Это происходит потому, что, когда вы пишете

var foo = {};
foo.x = foo = {n: b} //a=b=c

во время выполнения строки foo указывает на {}, но когда этот оператор разбивается на

foo.x = (foo = {n: b}) /a=(b=c)

Ссылка foo изменилась с {} на {n:b}, но foo в foo.x (a) все еще указывает на старую ссылку foo, поскольку выражение слева было оценено до начала назначения.

В соответствии с spec

  • Если LeftHandSideExpression не является объектом ObjectLiteral, ни ArrayLiteral,

    а. то Пусть lref - результат оценки ЛевостороннееВыражение.

Это означает, что перед присваиванием foo.x все еще была ссылка на старый foo.

Итак, если вы немного подберете свой пример, сделав

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

В этом примере вы не изменили ссылку на foo, но назначили новое свойство, поэтому теперь выходим

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

Теперь он сохранил ссылку на старый foo, поскольку новая ссылка не была назначена, поэтому сохраняются все свойства z, n и x.

Ответ 2

С

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

Ведущий foo.x частично оценивается сначала, достаточно, чтобы определить точную цель для назначения, прежде чем приступить к его фактическому назначению.

Он ведет себя больше по строкам:

var oldFoo = foo;
foo = {n: b};
oldFoo.x = foo;

Это указано в стандарте. Левая часть = оценивается (1.a) до того, как значение помещено туда (1.f):

Выделение присваивания: LeftHandSideExpression = Выделение присвоения

1) Если LeftHandSideExpression не является ObjectLiteral или ArrayLiteral, значит, a) Пусть lref является результатом оценки LeftHandSideExpression.
...
f) Выполнить? PutValue (lref, rval).

Ответ 3

Он равен

let tmp = foo;
foo = {n: b};
tmp.x = foo;

Вы могли видеть, что старый foo (сохраненный в z в этом примере) был изменен:

> z=foo={};
{}
> foo.x = foo = {n: b};
{ n: 10 }
> foo
{ n: 10 }
> z
{ x: { n: 10 } }

Ответ 4

Я понял.

var foo = {}; // now foo is a reference point to object {}
foo.x = foo = {n:1}; // first foo is refer to a new object {n:1}, then old foo referred object {} set a prop x

// try this to get what you want
var foo = foo1 = {};
foo.x = foo = {n:1};
console.log(foo, foo1) // here foo1 is what you want