โซนตายชั่วคราวคืออะไร


150

ฉันได้ยินมาว่าการเข้าถึงletและconstค่านิยมก่อนที่จะเริ่มต้นสามารถทำให้เกิดReferenceErrorเพราะสิ่งที่เรียกว่าเขตตายชั่วคราวเขตตายชั่วคราว

โซนตายชั่วคราวคืออะไรมันเกี่ยวข้องกับขอบเขตและการชักรอกอย่างไรและในสถานการณ์ใดที่พบ


6
มีความเป็นไปได้ที่ซ้ำกันของตัวแปรประกาศพร้อมหรือไม่คงที่ใน ES6 หรือไม่ - แม้ว่าคำถามไม่ได้มุ่งเน้นไปที่ TDZ แต่คำตอบก็เหมือนกัน
Bergi

คำตอบ:


201

letและconstมีความแตกต่างสองประการจากvar:

  1. พวกเขาเป็นบล็อกขอบเขต
  2. การเข้าถึง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)

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
}());

เครดิต: Temporal Dead Zone (TDZ) demystified

การเข้าถึงในขอบเขตด้านในยังคงทำให้เกิด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 transpiler เปิดโหมด "การปฏิบัติที่สูง" ที่จะใช้มันในREPL จัดหาes6.spec.blockScopingแฟล็กเพื่อใช้กับ CLI หรือเป็นไลบรารี

แนะนำอ่านเพิ่มเติม: TDZ demystifiedและES6 อนุญาต, Const และ“ชั่วตายโซน” (TDZ) ในความลึก



@zeroflagL ลิงค์ดีขอบคุณ นอกจากนี้ยังมีข้อความว่า: "foo ไม่ได้ประกาศไม่เป็นภาษาเริ่มต้น" ภาษานั้นจะเป็นประโยชน์ในการชี้แจง / แก้ไขในคำตอบข้างต้น let fooในบล็อกทำให้ยกขึ้นและประกาศที่ด้านบนของบล็อกนั้น สายของlet fooสาเหตุที่จะเริ่มต้น และfoo = xyzทำให้มันถูกกำหนดค่า
AJP

2
ฉันคิดว่านี่เป็นโพสต์ที่ยอดเยี่ยม! อย่างไรก็ตามฉันอยู่ภายใต้การแสดงผลที่ 'ปล่อย' ไม่ถูกชักรอก? ฉันพบสิ่งนี้ในเอกสาร doc ของ Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ …ฉันไม่ได้พยายามที่จะเป็น curmudgeon ฉันแค่อยากรู้อยากเห็นและเปิดให้ชี้แจง
dmarges

1
@jeows หน้า MDN ยังบอกว่าไม่ยก คุณควรพยายามแก้ไขสิ่งนั้นหากคุณมั่นใจในสิ่งที่คุณพูดอย่างแท้จริง ฉันคิดว่าฉันควรโพสต์คำถามเกี่ยวกับเรื่องนั้น
doubleOrt

1
@ Joews IMO คุณสามารถพูดได้ว่าพวกเขาถูกชักรอก แต่พวกเขาไม่สามารถเข้าถึงได้ก่อนที่จะถึงการประกาศเนื่องจาก TDZ หรือคุณอาจบอกว่าพวกเขาไม่ได้ถูกชักรอก แต่ TDZ จะทำให้การอ้างอิงใด ๆ เกิดข้อผิดพลาด จวนงบทั้งสองเป็นจริงอย่างเท่าเทียมกัน ยกเว้นฉันคิดว่าคุณกำลังใช้คำว่า "hoisting" ในแง่นามธรรมเช่นเดียวกับ "hoisting = เมื่อใดก็ตามที่เครื่องยนต์รับรู้ถึงการมีอยู่ของตัวแปรนั้น" นั่นเป็นเหตุผลทำไม นอกจากนี้สเปคพูดว่าอะไร
doubleOrt

7

การชักรอก:
let , const, varทุกคนได้รับการยกกระบวนการ
(หมายถึงอะไรพวกเขาไปด้านบนและประกาศที่ด้านบนของขอบเขต)

initialisation:

  • var ผ่านไปยังกระบวนการเริ่มต้นและรับค่าเริ่มต้นเป็น undefinedเป็น
  • ในขณะที่let, constไม่ได้ไปโยนกระบวนการเริ่มต้นดังนั้นค่าของพวกเขายังคงไม่สามารถเข้าถึงได้แม้ว่าพวกเขาประกาศแล้ว อะไรใส่ไว้ในtemporal dead zone

ดังนั้นในไม่ช้า:

กระบวนการ hoisting: var, let, const
กระบวนการ initialisation: var


0

ในกรณีของตัวแปร let และ const โดยทั่วไป Temporal Dead Zone เป็นโซน

"ก่อนที่จะประกาศตัวแปรของคุณ",

เช่นที่คุณไม่สามารถเข้าถึงค่าของตัวแปรเหล่านี้มันจะโยนข้อผิดพลาด

อดีต

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) การประกาศของvar aยกขึ้นรหัส inifialisation ที่ส่งaถึง 5 นั้นไม่ใช่
traktor53

ใช่ถูกต้อง a ถูกยกโดยไม่มีการเริ่มต้นใด ๆ ดังนั้นจะไม่ได้กำหนด
niranjan harpale

ตัวอย่างที่ยกมาไม่ถูกต้องโปรดแก้ไขหรือลบออก
เว็บของ Spidi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.