Как работает 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