Вроде как в коде ниже и всё должно быть просто, но тем не менее принцип работы не поддаётся моему пониманию.
При присваивании foo.x = foo = obj, как я понимаю, сначала выполняется правый участок кода, то есть в переменную "foo" заносится ссылка на объект {n:2} из переменной obj, и потом в свойство "foo.x" должна вроде как заноситься аналогичная ссылка, но выходит undefined. Может кто-то объяснить из-за чего подобное происходит?
let foo = {};
let obj = {n:2};
foo.x = foo = obj;
console.log(foo.x);
console.log(foo);
console.log(obj);
Другие участники пытаются донести мысль, что при выполнении строки foo.x = foo = obj; имена объектов сначала разыменовываются, как бы заменяются указателями на объекты.
Объектов два, давайте обозначим их A и B. Изначально foo указывает на A, obj на B. Тогда та строка превратится в такую последовательность действий:
Разыменование, которое превращает foo.x = ... в нечто вроде A.x = ... То, как это устроено, детально поясняет ответ от Igor.
Положить в переменную foo ту же ссылку, что в переменной obj. Теперь они обе указывают на B.
Положить в поле x объекта A ссылку из переменной foo. Спасибо разыменовыванию.
Вот небольшое изменение исходного кода, которое поможет лучше понять ситуацию:
let foo = {}; // A
let old_foo = foo; // сохраним A
let obj = {n:2}; // B
foo.x = foo = obj;
// foo указывает на B
// A.x = *foo = B
console.log(foo.x); // B.x = undefined
console.log(foo); // B
console.log(obj); // B
console.log(old_foo); // сохранённное A
Как показывает вывод, объект А никуда не делся, просто раньше на него была потеряна ссылка, а присвоение поля x прошло корректно, хоть и не на тот объект, который кажется очевидным.
let holder = { _foo: {} };
Object.defineProperty(holder, 'foo', {
get() {
return this._foo;
},
set(value)
{
console.log("set foo", value);
this._foo = value;
}
});
Object.defineProperty(holder.foo, 'x', {
get() {
return this._x;
},
set(value)
{
console.log("set foo.x", value);
this._x = value;
}
});
holder.foo.x = holder.foo = {n:2};
console.log(holder);
console.log(holder.foo);
Дело в том, что объекты в JS содержат не поля, а свойства.
Представьте, что нет свойств, а есть только гетеры и сетеры:
holder.getFoo().setX((holder.setFoo({ n: 2 }), holder.getFoo()));
Функция setX вызовется, хотя метода setX у результа вызова holder.getFoo в этот момент уже не будет.
Потому что foo.x изначально undefined, а раз выскочил undefined, то js его сразу вернет и продолжит выполнение следующих команд. Так что нужно что-то запихнуть в свойство foo.x.
Например вот так
let foo = {};
let obj = {
n: 2
};
foo.x = obj.n;
console.log(foo.x);
console.log(foo);
console.log(obj);
Продвижение своими сайтами как стратегия роста и независимости