What is purpose of let
getting hoisted to top when it will throw an error on accessing?
Đó là vì vậy chúng tôi có thể có phạm vi khối, đó là khái niệm khá dễ hiểu, mà không có khối tương đương với var
cẩu, mà là một nguồn truyền thống của lỗi và hiểu lầm.
xem xét bên trong khối này:
{
let a = 1;
console.log(a);
let b = 2;
console.log(a, b);
let c = 3;
console.log(a, b, c);
}
Các nhà thiết kế có ba lựa chọn chính ở đây:
- Có phạm vi khối nhưng với tất cả các tờ khai kéo lên đầu trang và dễ tiếp cận (như
var
là trong các chức năng); hoặc
- Không có phạm vi chặn và thay vào đó có phạm vi bắt đầu mới với mỗi
let
, const
, class
, v.v ...; hoặc
- Có phạm vi khối, với treo (hoặc những gì tôi gọi là "nửa treo"), nơi mà các tờ khai được kéo lên, nhưng định danh họ tuyên bố là không thể tiếp cận cho đến khi họ đang đạt được trong mã
Tùy chọn 1 để chúng tôi mở ra cùng một loại lỗi mà chúng tôi có với var
cẩu. Tùy chọn 2 là cách cách phức tạp hơn để mọi người hiểu và nhiều công việc hơn cho công cụ JavaScript để thực hiện (chi tiết bên dưới nếu bạn muốn). Tùy chọn 3 truy cập vào vị trí ngọt ngào: Phạm vi khối dễ hiểu và dễ triển khai và TDZ ngăn chặn các lỗi giống như lỗi gây ra bởi việc lắp đặt var
.
Also do var
also suffer from TDZ,I know when it will throw undefined
but is it because of TDZ?
Không, var
tuyên bố không có TDZ. undefined
không phải là ném, nó chỉ là giá trị mà một biến có khi được khai báo nhưng không được đặt thành bất kỳ thứ gì khác (chưa). var
khai báo được đưa lên đầu của hàm hoặc môi trường toàn cục và có thể truy cập đầy đủ trong phạm vi đó, ngay cả trước khi đạt được dòng var
.
Nó có thể giúp hiểu được cách thức giải quyết nhận dạng được xử lý trong JavaScript:
Các đặc điểm kỹ thuật định nghĩa nó trong điều kiện của một cái gì đó gọi là lexical environment, which contains an environment record, chứa các thông tin về các biến, hằng số, thông số chức năng (nếu có liên quan), class
tuyên bố, v.v. cho ngữ cảnh hiện tại. (A context là một thực thi cụ thể của một phạm vi. Tức là, nếu chúng ta có một hàm gọi là example
, phần thân của example
định nghĩa một phạm vi mới, mỗi lần chúng ta gọi là example
, có các biến mới, v.v. — đó là bối cảnh.)
các thông tin về một định danh (biến, vv), được gọi là một ràng buộc. Nó chứa tên của định danh, giá trị hiện tại của nó và một số thông tin khác về nó (như là nó có thể thay đổi hoặc không thay đổi được, cho dù nó có thể truy cập được chưa, vv).
Khi thực thi mã nhập một ngữ cảnh mới (ví dụ, khi hàm được gọi, hoặc nhập một khối có chứa let
hoặc tương tự), công cụ JavaScript sẽ tạo * một đối tượng môi trường từ vựng mới (LEO), với môi trường của nó ghi lại (envrec), và cung cấp cho LEO một liên kết đến LEO "bên ngoài" có chứa nó, tạo thành một chuỗi. Khi động cơ cần tìm kiếm một mã định danh, nó tìm kiếm một ràng buộc trong envrec của LEO trên cùng và, nếu tìm thấy, sử dụng nó; nếu không tìm thấy, hãy nhìn vào LEO tiếp theo trong chuỗi, v.v. cho đến khi chúng ta đến cuối chuỗi. (Bạn có thể đã đoán: Liên kết cuối cùng trong chuỗi là dành cho môi trường toàn cầu.)
Những thay đổi trong ES2015 để kích hoạt phạm vi chặn và let
, const
, v.v.đã cơ bản:
- Một LEO mới có thể được tạo ra cho một khối, nếu khối có chứa khai báo khối chỉnh phạm vi
- Bindings trong một LEO thể được đánh dấu "không thể tiếp cận" nên TDZ có thể được thi hành
với tất cả những gì trong tâm trí, chúng ta hãy nhìn vào mã này:
function example() {
console.log("alpha");
var a = 1;
let b = 2;
if (Math.random() < 0.5) {
console.log("beta");
let c = 3;
var d = 4;
console.log("gamma");
let e = 5;
console.log(a, b, c, d, e);
}
}
Khi example
được gọi là, làm thế nào để động cơ xử lý đó (ít nhất, về mặt spec)? Như thế này:
- Nó tạo ra một LEO cho bối cảnh của cuộc gọi để
example
- Nó cho biết thêm bindings cho
a
, b
và d
để envrec của LEO rằng, tất cả với giá trị undefined
:
a
được thêm vào vì nó là một liên kết var
nằm ở bất kỳ vị trí nào trong hàm. Cờ "có thể truy cập" được đặt thành true (vì var
).
b
được thêm bởi vì đó là một liên kết let
ở cấp cao nhất của hàm; cờ "có thể truy cập" được đặt thành false bởi vì chúng tôi chưa đạt đến dòng let b
.
d
vì đó là một liên kết var
, như a
.
- Nó thực hiện
console.log("alpha")
.
- Nó thực hiện
a = 1
, thay đổi giá trị của ràng buộc cho a
từ undefined
thành 1
.
- Nó thực hiện
let b
, thay đổi cờ "có thể truy cập" của ràng buộc b
thành true.
- Nó thực hiện
b = 2
, thay đổi giá trị của liên kết cho b
từ undefined
thành 2
.
- Nó đánh giá
Math.random() < 0.5
; giả sử đó là sự thật:
- Bởi vì khối chứa định danh khối chỉnh phạm vi, động cơ sẽ tạo ra một LEO mới cho khối, thiết lập "bên ngoài" của nó LEO đến một trong những tạo ra trong Bước 1.
- Nó cho biết thêm bindings cho
c
và e
với sự ghen tị của LEO, với cờ "có thể truy cập" được đặt thành false và giá trị được đặt thành undefined
.
- Nó thực hiện
console.log("beta")
.
- Nó thực hiện
let c
, đặt cờ "có thể truy cập" của c
của ràng buộc thành đúng
- Nó thực hiện
c = 3
.
- Nó thực hiện
d = 4
.
- Nó thực hiện
console.log("gamma")
.
- Nó thực thi
let e
, đặt cờ "có thể truy cập" của ràng buộc e
thành true.
- Nó thực hiện
e = 5
.
- Nó thực hiện
console.log(a, b, c, d, e)
.
Hy vọng rằng câu trả lời:
- Tại sao chúng ta có
let
nửa treo (để làm cho nó dễ dàng để hiểu được phạm vi, và để tránh việc có quá nhiều Sư Tử và envrecs, và để tránh lỗi ở mức khối giống như những người var
cẩu có ở cấp chức năng)
- tại sao
var
không có TDZ ("tiếp cận" cờ một var
biến của ràng buộc luôn là true)
* Ít nhất, đó là những gì họ làm về đặc điểm kỹ thuật. Trong thực tế, họ có thể làm bất cứ điều gì họ thích cung cấp nó hoạt động như các đặc điểm kỹ thuật xác định. Trên thực tế, hầu hết các công cụ sẽ hoạt động hiệu quả hơn, sử dụng ngăn xếp, v.v.
Bản sao có thể có của từ khóa ["let" so với từ khóa "var"] (http://stackoverflow.com/questions/762011/let -keyword-vs-var-keyword) –
@ MarcosPérezGudemy nghi ngờ có liên quan đến cẩu. Do cẩu để cho làm cho bất kỳ sự khác biệt mặc dù nó ném một lỗi khi truy cập. Nhưng liên kết bạn chia sẻ cho chúng tôi biết thêm về sự khác biệt giữa let và var – brk
Ok xin lỗi, tôi không biết cẩu là gì, nhưng bây giờ tất cả là rõ ràng. Tôi xóa phiếu bầu trùng lặp của mình. –