Що таке тимчасова мертва зона?


150

Я чув, що доступ letі constзначення перед їх ініціалізацією можуть викликати причину ReferenceErrorтого, що називається тимчасовою мертвою зоною .

Що таке тимчасова мертва зона, як вона стосується сфери застосування та підйому, і в яких ситуаціях вона стикається?


6
можливий повторник Чи є змінні, декларовані з дозволом або const, не піднімаються в ES6? - хоча питання не фокусується на TDZ, відповіді в основному однакові
Bergi

Відповіді:


201

letі constмають дві широкі відмінності від var:

  1. Вони є блок-діапазоном .
  2. Отриманий результат varдо доступу до його оголошення undefined; доступ до 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), але є період між введенням і обсяг оголошується , де вони не можуть бути доступні. Цей період є тимчасовою мертвою зоною (ТДЗ) .

Протяжен закінчується , коли 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.

TDP не включений за замовчуванням у транспілері babel.js . Увімкніть режим "високої відповідності", щоб використовувати його в системі REPL . Поставте es6.spec.blockScopingпрапор, щоб використовувати його з CLI або як бібліотеку.

Рекомендовано для подальшого читання: демістифіковані TDZ та ES6 Let, Const та "тимчасова мертва зона" (TDZ) у глибині .



@zeroflagL гарне посилання, дякую. Також сказано: "foo не є незадекларованим, він неініціалізований", ця мова була б корисно уточнити / виправити у відповіді вище. let fooв блоці викликає його підняття та оголошення вгорі цього блоку. Рядок let fooпричин її ініціалізації. І foo = xyzвикликає присвоєння йому значення.
AJP

2
Я думаю, що це чудовий пост! Однак у мене було враження, що "пускати" не підлягали підйомам? Я виявив це в документах Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Я не намагаюся бути кур'єром, мені просто цікаво і я відкритий для роз'яснення.
dmarges

1
@jeows Сторінка MDN все ще говорить, що їх не піднімають. Спробуйте це відредагувати, якщо ви справді впевнені в тому, що говорите. Думаю, я повинен поставити питання з цього приводу.
подвійнийокт

1
@joews IMO, ви можете сказати, що вони піднімаються, але до них не можна отримати доступ до їх декларації через TDZ, або ви можете сказати, що вони не піднімаються, але TDZ спричинить помилки на них. Практично обидва твердження однаково вірні. Крім того, я думаю, ви використовуєте термін "вантажопідйомність" в абстрактному розумінні, як в "вантажопідйомності = всякий раз, коли двигун знає про існування цієї змінної". Це чому? Плюс, що кажуть на це специфікації?
подвійнийОкт

7

Вантажопідйомні:
let , const, varвсе прибудете поставили процес.
(що означає, що вони переходять у верхню частину та оголошують у верхній частині області.)

Ініціалізація:

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

Отже коротко:

Процес підйому: var, let, const
ініціалізація процесу: var


0

У випадку змінних 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 без будь-якої ініціалізації. Тож заповіт буде невизначеним.
niranjan harpale

Перший цитований приклад - це не так, будь ласка, виправте його або видаліть.
Мережа Спіді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.