Почему foo.x = undefined?

114
17 января 2021, 13:10

Вроде как в коде ниже и всё должно быть просто, но тем не менее принцип работы не поддаётся моему пониманию.

При присваивании 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); 
        

Answer 1

Другие участники пытаются донести мысль, что при выполнении строки foo.x = foo = obj; имена объектов сначала разыменовываются, как бы заменяются указателями на объекты.

Объектов два, давайте обозначим их A и B. Изначально foo указывает на A, obj на B. Тогда та строка превратится в такую последовательность действий:

  1. Разыменование, которое превращает foo.x = ... в нечто вроде A.x = ... То, как это устроено, детально поясняет ответ от Igor.

  2. Положить в переменную foo ту же ссылку, что в переменной obj. Теперь они обе указывают на B.

  3. Положить в поле 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 прошло корректно, хоть и не на тот объект, который кажется очевидным.

Answer 2

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 в этот момент уже не будет.

Answer 3

Потому что 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);

READ ALSO
Как сделать растягивание как в excel для таблицы?

Как сделать растягивание как в excel для таблицы?

Есть простая таблица, нужно, чтобы при нажатии на поле, у него появлялась обвода и его можно было растянуть на другие поля (выше, ниже)

119
Javascript фильтр таблиц

Javascript фильтр таблиц

В таблице есть столбец с адресами формата: "город" + "улица и дом"Значения в таблицу попадают из json файла

113
Склеивание полигонов в Yandex API

Склеивание полигонов в Yandex API

В Yandex APi JS допустим когда сначала рисуешь один полигон затем рядом еще один полигон предусматривается автоматическое "cклеивание" границ...

91