Очередность присвоения и смена ссылок на объекта
Встретил интересную задачу.
Задача: Чему будет равно foо.x?
var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};
Ответ: undefined.
Насколько я понимаю, foo.x, на последней строке, ссылается на старую ссылку foo, при этом, присваивая свойству x значение новой ссылки foo. Как в этом случае работает присвоение и замена ссылки для foo?
Ответы (2 шт):
Согласно спецификации:
- выражение
foo.x = foo = {n: 2};рассматривается какfoo.x = (foo = {n: 2}); - при выполнении присваивания
leftExpression = expressin:- сначала вычисляется leftExpression, для получения места куда присваивать
- затем вычисляется expressin
- выполняется непосредственно присваивание.
Для примера в вопросе
- "вычисляется"
foo.x- в данном случаеfooэто объект сохраненный вbar - "вычисляется"
foo = {n: 2}- вычисляется
foo- в данном случае это объект сохраненный вbar - вычисляется
{n: 2} - в переменную
fooприсваивается значения из2.1
- вычисляется
- в сохраненную
fooв полеxприсваивается значение вычисленное в пункте 2
Таким образом, ссылка на новый foo доступна через переменную bar
var foo = {
n: 1
};
var bar = foo;
foo.x = foo = {
n: 2
};
console.log(foo);
console.log(bar)
Вот объяснение, которое я нашел для себя.
foo.x = (foo = {n: 2});
- На первом этапе вычисляется
leftExpression, а этоfoo.x
leftExpression = expression
Далее вычисляется права часть
expression. Для этого выраженияfooстановится ссылкой на новый объект (foo = {n: 2})Вычисления из первого пункта становятся недействительны. Поскольку, чтобы в
foo.xбыло что-то записано, нужно чтобы ссылка на объект существовала, а она только что была изменена при этом присвоении:foo = {n: 2}.Исходя из пункта 3: смотрим
foo.xвыдаетсяundefined, как и должно было.При этом во время присвоения
foo.xэта же ссылка все еще сохранена в bar, поэтому в bar будет создано новое свойство x со значением в виде ссылки на объект{n: 2}. В результате чегоbar.x == fooвыдастtrue(одна и та же ссылка на объект)