Что такое временная мертвая зона?


162

Я слышал, что доступ к значениям letи constзначениям до их инициализации может вызвать ошибку ReferenceErrorиз-за того, что называется временной мертвой зоной .

Что такое временная мертвая зона, как она связана с прицелом и подъемом и в каких ситуациях встречается?


6
возможный дубликат переменных, объявленных с помощью let или const, не поднят в ES6? - хотя вопрос не касается TDZ, ответы в основном те же,
Берги

Ответы:


210

letи constимеют два основных отличия от var:

  1. Они имеют блочную область видимости .
  2. Доступ к a varдо его объявления дает результат undefined; доступ к a letили constдо того, как он объявлен, бросает ReferenceError:

console.log(aVar); // undefined
console.log(aLet); // causes ReferenceError: aLet is not defined
var aVar = 1;
let aLet = 2;

Из этих примеров видно, что letобъявления (и const, который работает таким же образом) не могут быть подняты , поскольку aLetони не существуют до того, как им будет присвоено значение.

Это не так, however- letи const которые поднимают (например var, classи function), но есть период между вводом и объем объявляется , где они не могут быть доступны. Этот период является временной мертвой зоной (TDZ) .

Протяжен заканчивается , когда aLetбудет объявлен , а не назначается :

//console.log(aLet)  // would throw ReferenceError

let aLet;
console.log(aLet); // undefined
aLet = 10;
console.log(aLet); // 10

Этот пример показывает, что letподнимается:

let x = 'outer value';
(function() {
  // start TDZ for x
  console.log(x);
  let x = 'inner value'; // declaration ends TDZ for x
}());

Кредит: Демистификация временной мертвой зоны (TDZ)

Доступ xво внутренней области по-прежнему вызывает ошибку ReferenceError. Если бы letне были подняты, он бы залез outer value.

TDZ - это хорошо, потому что он помогает выявить ошибки - доступ к значению до того, как оно было объявлено, редко бывает преднамеренным.

TDZ также применяется к аргументам функции по умолчанию. Аргументы оцениваются слева направо, и каждый аргумент находится в TDZ, пока не будет назначен:

// b is in TDZ until its value is assigned
function testDefaults(a=b, b) { }
testDefaults(undefined, 1); // throws ReferenceError because the evaluation of a reads b before it has been evaluated.

TDZ по умолчанию отключен в транспиляторе babel.js. Включите режим «высокого соответствия», чтобы использовать его в REPL . Поставьте es6.spec.blockScopingфлаг, чтобы использовать его с CLI или как библиотеку.

Рекомендуемая дополнительная литература: демистификация TDZ и ES6 Let, Const и «Temporal Dead Zone» (TDZ) in Depth .



@zeroflagL хорошая ссылка, спасибо. Также он говорит: «foo не необъявлен, он не инициализирован», этот язык было бы полезно уточнить / исправить в ответе выше. let fooin a block заставляет его поднять и объявить в верхней части этого блока. Строка, let fooвызывающая его инициализацию. И foo = xyzзаставляет его присвоить значение.
AJP

2
Я считаю, что это отличный пост! Однако у меня создалось впечатление, что «let» не подлежит подъему? Я нашел это в документации Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Я не пытаюсь быть скрягой, мне просто было любопытно, и я открыт для разъяснений.
dmarges

1
@jeows На странице MDN все еще написано, что они не подняты. Вам следует попробовать отредактировать это, если вы действительно уверены в том, что говорите. Думаю, мне стоит задать вопрос по этому поводу.
doubleOrt 05

1
@joews IMO, вы можете либо сказать, что они подняты, но к ним нельзя получить доступ, прежде чем их объявление будет достигнуто из-за TDZ, либо вы можете сказать, что они не подняты, но TDZ вызовет любые ссылки на них, чтобы вывести ошибку. Практически оба утверждения одинаково верны. Кроме того, я думаю, вы используете термин «подъем» в абстрактном смысле, например, «подъем = всякий раз, когда движок знает о существовании этой переменной». Вот почему? Плюс, что об этом говорят спецификации?
doubleOrt

8

Грузоподъемные:
let , const, varвсе прибудете водрузили процесс.
(что означает, что они поднимаются выше и объявляют в верхней части области видимости.)

Инициализация:

  • varпройти также начальный процесс и получить начальное значение undefined.
  • в то время как let, constне пошел бросать начальный процесс, поэтому их значения все еще недоступны, хотя они уже объявлены. что их вtemporal dead zone

Итак, вкратце:

Процесс подъема: var, let, const
инициализация процесса: var


2

В случае переменных let и const, по сути, временная мертвая зона - это зона

"до объявления вашей переменной",

т.е. если вы не можете получить доступ к значениям этих переменных, это вызовет ошибку.

напр.

let sum = a + 5;        //---------
//some other code       //         | ------>  this is TDZ for variable a
                        //         |
console.log(sum)        //---------
let a = 5;

приведенный выше код дает ошибку

тот же код не выдаст ошибку, когда мы используем var для переменной 'a',

напр.

var sum = a;                            
console.log(sum)     //prints undefined
var a = 5;

во втором примере консольный журнал выдает «NaN» (результат добавления undefinedи 5). Declaratation из var aподнят, то inifialisation код Настраивает a5 не.
traktor53

да, верно, a поднимается без какой-либо инициализации. Таким образом, a будет неопределенным.
niranjan harpale 04

Первый приведенный пример неверен, исправьте или удалите его.
Spidi's Web,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.