var a = {}
var b = {}
try{
a.x.y = b.e = 1 // Uncaught TypeError: Cannot set property 'y' of undefined
} catch(err) {
console.error(err);
}
console.log(b.e) // 1
var a = {}
var b = {}
try {
a.x.y.z = b.e = 1 // Uncaught TypeError: Cannot read property 'y' of undefined
} catch(err) {
console.error(err);
}
console.log(b.e) // undefined
javascript
operators
order-of-execution
Кевин Аскин
источник
источник
b.z = 1
иb.e = 1
выполнить первое (учитывая правую ассоциативность на=
), а затемa.x.y.z = ...
выполнить и не; почемуb
присвоение выполняется в одном случае, а в другом - нет?y
не существует наa.x
; но это верно в обоих случаях. Почему он предотвращает правостороннее присваивание во втором случае, но не в первом? Чем отличается порядок исполнения? (Я упомянул синтаксическую ошибку, потому что время синтаксической ошибки сильно отличается от времени ошибки времени выполнения.)Ответы:
На самом деле, если вы правильно прочитали сообщение об ошибке, варианты 1 и 2 вызывают разные ошибки.
Дело
a.x.y
:Дело
a.x.y.z
:Думаю, лучше всего описать это пошаговым исполнением на простом английском.
Случай 1
Случай 2
В комментариях Соломон Тэм нашел эту документацию ECMA об операции присваивания .
источник
Порядок операций становится более ясным, когда вы используете оператор запятой внутри скобок, чтобы увидеть, какие части выполняются, когда:
Смотрим на спецификацию :
PutValue
это то, что бросаетTypeError
:Ничто не может быть присвоено свойству
undefined
-[[CanPut]]
внутренний методundefined
всегда будет возвращатьfalse
.Другими словами: интерпретатор анализирует левую часть, затем анализирует правую часть, а затем выдает ошибку, если свойство в левой части не может быть присвоено.
Когда ты делаешь
Левая часть успешно анализируется , пока не
PutValue
будет вызвана; тот факт, что.x
свойство оценивается как значениеundefined
, не рассматривается до тех пор, пока не будет проанализирована правая часть. Интерпретатор видит это как «Присвойте какое-либо значение свойству« y », равному undefined», а присвоение свойствуundefined
только значения бросает внутрьPutValue
.Напротив:
Интерпретатор никогда не доходит до точки, где он пытается назначить
z
свойство, потому что сначала он должен разрешитьa.x.y
значение. Еслиa.x.y
разрешить значение (даже доundefined
), все будет в порядке - внутри будет выдана ошибка,PutValue
как указано выше. Но при доступеa.x.y
возникает ошибка, потому что свойствоy
недоступноundefined
.источник
Рассмотрим следующий код:
Грубая схема шагов , необходимых для выполнения кода выглядит следующим образом исх :
a.x.y
возвращает ссылку ссылки, состоящую из базового значенияa.x
(undefined) и указанного имени (y
).y
undefined значение. Это должно вызвать исключение TypeError ref .источник