ECMAScript 6 giới thiệu các let
tuyên bố .
Tôi đã nghe nói rằng nó được mô tả như một biến "cục bộ", nhưng tôi vẫn không hoàn toàn chắc chắn về cách nó hoạt động khác với var
từ khóa.
Sự khác biệt là gì? Khi nào nên let
sử dụng hơn var
?
ECMAScript 6 giới thiệu các let
tuyên bố .
Tôi đã nghe nói rằng nó được mô tả như một biến "cục bộ", nhưng tôi vẫn không hoàn toàn chắc chắn về cách nó hoạt động khác với var
từ khóa.
Sự khác biệt là gì? Khi nào nên let
sử dụng hơn var
?
Câu trả lời:
Sự khác biệt chính là quy tắc phạm vi. Các biến khai báo bằng var
từ khoá được scoped đến cơ quan chức năng ngay lập tức (do đó phạm vi chức năng) trong khi let
các biến được scoped đến ngay lập tức kèm theo khối ký hiệu bằng { }
(do đó phạm vi khối).
function run() {
var foo = "Foo";
let bar = "Bar";
console.log(foo, bar);
{
let baz = "Bazz";
console.log(baz);
}
console.log(baz); // ReferenceError
}
run();
Lý do tại sao let
từ khóa được giới thiệu cho ngôn ngữ là phạm vi chức năng gây nhầm lẫn và là một trong những nguồn lỗi chính trong JavaScript.
Hãy xem ví dụ này từ một câu hỏi stackoverflow khác :
var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value: " + i);
};
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
My value: 3
là đầu ra cho bàn điều khiển mỗi lần funcs[j]();
được gọi vì các hàm ẩn danh được liên kết với cùng một biến.
Mọi người phải tạo ra các hàm được gọi ngay lập tức để thu được giá trị chính xác từ các vòng lặp nhưng đó cũng là lông.
Trong khi các biến được khai báo bằng var
từ khóa được nâng lên (khởi tạo undefined
trước khi mã được chạy), điều đó có nghĩa là chúng có thể truy cập được trong phạm vi kèm theo ngay cả trước khi chúng được khai báo:
function run() {
console.log(foo); // undefined
var foo = "Foo";
console.log(foo); // Foo
}
run();
let
các biến không được khởi tạo cho đến khi định nghĩa của chúng được đánh giá. Truy cập chúng trước khi kết quả khởi tạo trong a ReferenceError
. Biến được cho là ở "vùng chết tạm thời" từ khi bắt đầu khối cho đến khi quá trình khởi tạo được xử lý.
function checkHoisting() {
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
}
checkHoisting();
Ở cấp cao nhất, let
không giống như var
, không tạo ra một thuộc tính trên đối tượng toàn cầu:
var foo = "Foo"; // globally scoped
let bar = "Bar"; // globally scoped
console.log(window.foo); // Foo
console.log(window.bar); // undefined
Trong chế độ nghiêm ngặt, var
sẽ cho phép bạn khai báo lại cùng một biến trong cùng phạm vi trong khi let
tăng SyntaxError.
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
let
biểu thức khối let (variable declaration) statement
là không chuẩn và sẽ bị xóa trong tương lai, bugzilla.mozilla.org/show_orms.cgi?id=1023609 .
let
cũng có thể được sử dụng để tránh các vấn đề với việc đóng cửa. Nó liên kết giá trị mới thay vì giữ một tham chiếu cũ như trong các ví dụ dưới đây.
for(var i=1; i<6; i++) {
$("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>
Mã ở trên thể hiện một vấn đề đóng JavaScript cổ điển. Tham chiếu đến i
biến đang được lưu trữ trong bao đóng xử lý nhấp chuột, thay vì giá trị thực của i
.
Mỗi trình xử lý nhấp chuột duy nhất sẽ tham chiếu đến cùng một đối tượng vì chỉ có một đối tượng truy cập giữ 6 vì vậy bạn nhận được sáu đối tượng trên mỗi lần nhấp.
Một cách giải quyết chung là bọc cái này trong một hàm ẩn danh và chuyển qua i
làm đối số. Những vấn đề như vậy cũng có thể tránh được bằng cách sử dụng let
thay vào đó var
như được hiển thị trong đoạn mã dưới đây.
(Đã thử nghiệm trong Chrome và Firefox 50)
for(let i=1; i<6; i++) {
$("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>
let
, nhưng nó cảnh báo "6" cho tất cả các nút. Bạn có nguồn nào nói rằng let
phải cư xử thế nào không?
let
nó sẽ thực sự hữu ích. Đặt các trình lắng nghe sự kiện trong một vòng lặp không còn yêu cầu một biểu thức hàm được gọi ngay lập tức cho phạm vi cục bộ i
tại mỗi lần lặp.
let
và là var
gì?var
câu lệnh được biết trong toàn bộ hàm được xác định trong, từ khi bắt đầu hàm.(*)let
câu lệnh chỉ được biết đến trong khối mà nó được định nghĩa, kể từ thời điểm nó được xác định trở đi. (**)Để hiểu sự khác biệt, hãy xem xét mã sau đây:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Ở đây, chúng ta có thể thấy rằng biến của chúng ta j
chỉ được biết đến trong vòng lặp đầu tiên, nhưng không phải trước và sau. Tuy nhiên, biến của chúng tôii
được biết đến trong toàn bộ chức năng.
Ngoài ra, hãy xem xét rằng các biến trong phạm vi khối không được biết trước khi chúng được khai báo vì chúng không được nâng lên. Bạn cũng không được phép xác định lại cùng một biến trong phạm vi khối trong cùng một khối. Điều này làm cho các biến trong phạm vi khối dễ bị lỗi hơn các biến có phạm vi toàn cầu hoặc theo chức năng, được nâng lên và không tạo ra bất kỳ lỗi nào trong trường hợp khai báo nhiều lần.
let
ngày hôm nay?Một số người sẽ lập luận rằng trong tương lai, chúng ta sẽ CHỈ sử dụng các câu lệnh let và các câu lệnh var sẽ trở nên lỗi thời. Giáo sư JavaScript Kyle Simpson đã viết một bài viết rất công phu về lý do tại sao ông tin rằng sẽ không phải là trường hợp .
Hôm nay, tuy nhiên, đó chắc chắn không phải là trường hợp. Trong thực tế, chúng ta thực sự cần phải tự hỏi liệu nó có an toàn để sử dụng let
tuyên bố hay không. Câu trả lời cho câu hỏi đó phụ thuộc vào môi trường của bạn:
Nếu bạn đang viết mã JavaScript phía máy chủ ( Node.js ), bạn có thể sử dụng let
câu lệnh một cách an toàn .
Nếu bạn đang viết mã JavaScript phía máy khách và sử dụng trình chuyển đổi dựa trên trình duyệt (như Traceur hoặc babel- stand Độc ), bạn có thể sử dụng let
câu lệnh một cách an toàn , tuy nhiên mã của bạn có thể là bất cứ điều gì ngoài tối ưu về hiệu suất.
Nếu bạn đang viết mã JavaScript phía máy khách và sử dụng trình chuyển đổi dựa trên Node (như tập lệnh shell của dấu vết hoặc Babel ), bạn có thể sử dụng let
câu lệnh một cách an toàn . Và bởi vì trình duyệt của bạn sẽ chỉ biết về mã được dịch mã, nên hạn chế về hiệu suất.
Nếu bạn đang viết mã JavaScript phía máy khách và không sử dụng bộ chuyển mã, bạn cần xem xét hỗ trợ trình duyệt.
Vẫn còn một số trình duyệt hoàn toàn không hỗ trợ let
:
Đối với một cái nhìn tổng quan up-to-date trong đó các trình duyệt hỗ trợ let
tuyên bố tại thời điểm đọc của bạn câu trả lời này, xem này Can I Use
trang .
(*) Các biến phạm vi toàn cầu và chức năng có thể được khởi tạo và sử dụng trước khi chúng được khai báo vì các biến JavaScript được nâng lên . Điều này có nghĩa là các khai báo luôn luôn đứng đầu phạm vi.
(**) Khối biến phạm vi không được nâng lên
i
IS được biết đến ở mọi nơi trong khối chức năng! Nó bắt đầu như undefined
(do cẩu) cho đến khi bạn gán một giá trị! ps: let
cũng được nâng lên (đến đỉnh của khối chứa), nhưng sẽ đưa ra ReferenceError
khi được tham chiếu trong khối trước khi gán đầu tiên. (ps2: Tôi là một chàng trai chuyên nghiệp về dấu chấm phẩy nhưng bạn thực sự không cần một dấu chấm phẩy sau một khối). Điều đó đang được nói, cảm ơn vì đã thêm kiểm tra thực tế về hỗ trợ!
let
và var
!
let
và const
được khuyến nghị chỉ sử dụng khi bạn thực sự cần chức năng bổ sung của chúng , bởi vì việc thực thi / kiểm tra các tính năng bổ sung này (như const chỉ viết) dẫn đến 'công việc nhiều hơn '(và các nút phạm vi bổ sung trong cây phạm vi) cho (các) công cụ (hiện tại) để thực thi / kiểm tra / xác minh / thiết lập.
Đây là một lời giải thích của let
từ khóa với một số ví dụ.
let
hoạt động rất thíchvar
. Sự khác biệt chính là phạm vi của mộtvar
biến là toàn bộ hàm kèm theo
Bảng này trên Wikipedia cho thấy trình duyệt nào hỗ trợ Javascript 1.7.
Lưu ý rằng chỉ có trình duyệt Mozilla và Chrome hỗ trợ nó. IE, Safari và những người khác không có khả năng.
let
msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx
Câu trả lời được chấp nhận thiếu một điểm:
{
let a = 123;
};
console.log(a); // ReferenceError: a is not defined
for
khởi tạo vòng lặp, thu hẹp đáng kể phạm vi áp dụng các giới hạn của let
. Nâng cao.
let
Các biến được khai báo sử dụng let
từ khóa có phạm vi khối, có nghĩa là chúng chỉ có sẵn trong khối mà chúng được khai báo.
Ở cấp cao nhất, các biến được khai báo sử dụng let
không tạo thuộc tính trên đối tượng toàn cục.
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined
Bên trong một hàm (nhưng bên ngoài một khối), let
có cùng phạm vi với var
.
(() => {
var functionScopedVariable = 42;
let blockScopedVariable = 43;
console.log(functionScopedVariable); // 42
console.log(blockScopedVariable); // 43
})();
console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
Các biến được khai báo sử dụng let
bên trong một khối không thể được truy cập bên ngoài khối đó.
{
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
}
console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
Các biến được khai báo với let
các vòng lặp chỉ có thể được tham chiếu bên trong vòng lặp đó.
for (var i = 0; i < 3; i++) {
var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4
for (let k = 0; k < 3; k++) {
let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.
Nếu bạn sử dụng let
thay vì var
trong một vòng lặp, với mỗi lần lặp, bạn sẽ nhận được một biến mới. Điều đó có nghĩa là bạn có thể sử dụng một cách an toàn trong một vòng lặp.
// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0);
}
Do vùng chết tạm thời , các biến được khai báo sử dụng let
không thể được truy cập trước khi chúng được khai báo. Cố gắng để làm như vậy ném một lỗi.
console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;
Bạn không thể khai báo cùng một biến nhiều lần bằng cách sử dụng let
. Bạn cũng không thể khai báo một biến bằng cách sử dụng let
cùng một mã định danh như một biến khác được khai báo sử dụng var
.
var a;
var a; // Works fine.
let b;
let b; // SyntaxError: Identifier 'b' has already been declared
var c;
let c; // SyntaxError: Identifier 'c' has already been declared
const
const
là khá giống với let
phạm vi khối củaitit và có TDZ. Tuy nhiên, có hai điều khác nhau.
Biến được khai báo sử dụng const
không thể được chỉ định lại.
const a = 42;
a = 43; // TypeError: Assignment to constant variable.
Lưu ý rằng điều đó không có nghĩa là giá trị là bất biến. Thuộc tính của nó vẫn có thể được thay đổi.
const obj = {};
obj.a = 42;
console.log(obj.a); // 42
Nếu bạn muốn có một đối tượng bất biến, bạn nên sử dụng Object.freeze()
.
Bạn luôn phải chỉ định một giá trị khi khai báo một biến bằng cách sử dụng const
.
const a; // SyntaxError: Missing initializer in const declaration
Dưới đây là một ví dụ cho sự khác biệt giữa hai (hỗ trợ chỉ bắt đầu cho chrome):
Như bạn có thể thấy var j
biến vẫn có giá trị nằm ngoài phạm vi vòng lặp for (Phạm vi khối), nhưng let i
biến không được xác định bên ngoài phạm vi vòng lặp for.
"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
console.log(j);
}
console.log(j);
console.log("let:");
for (let i = 0; i < 2; i++) {
console.log(i);
}
console.log(i);
Có một số khác biệt tinh tế - let
phạm vi hoạt động giống như phạm vi biến đổi hơn trong bất kỳ ngôn ngữ nào khác.
ví dụ: Phạm vi của khối kèm theo, Chúng không tồn tại trước khi chúng được khai báo, v.v.
Tuy nhiên, đáng chú ý rằng đó let
chỉ là một phần của các triển khai Javascript mới hơn và có các mức độ hỗ trợ trình duyệt khác nhau .
let
được bao gồm trong dự thảo phiên bản thứ 6 và rất có thể sẽ nằm trong đặc tả kỹ thuật cuối cùng.
let
. Safari, IE và Chome đều không.
let
không cần nâng, để sử dụng một biến được xác định bởi một let
định nghĩa ở đầu khối của bạn. Nếu bạn có một if
câu lệnh không chỉ là một vài dòng mã, bạn có thể quên rằng bạn không thể sử dụng biến đó cho đến khi nó được xác định. ĐIỂM TUYỆT VỜI !!!
let
sẽ đưa biến lên đầu khối. Tuy nhiên, việc tham chiếu biến trong khối trước khi khai báo biến dẫn đến ReferenceError (lưu ý của tôi: thay vì cũ tốt undefined
). biến nằm trong 'vùng chết tạm thời' từ khi bắt đầu khối cho đến khi khai báo được xử lý. " Tương tự với "câu lệnh chuyển đổi vì chỉ có một khối bên dưới". Nguồn: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Sự khác biệt chính là sự khác biệt về phạm vi , trong khi cho phép chỉ có sẵn bên trong phạm vi được khai báo, như trong vòng lặp for, ví dụ var có thể được truy cập bên ngoài vòng lặp. Từ tài liệu trong MDN (ví dụ cũng từ MDN):
cho phép bạn khai báo các biến bị giới hạn phạm vi đối với khối, câu lệnh hoặc biểu thức mà nó được sử dụng. Điều này không giống như var từ khóa , định nghĩa một biến toàn cục hoặc cục bộ cho toàn bộ hàm bất kể phạm vi khối.
Các biến được khai báo bằng let có phạm vi của chúng là khối mà chúng được xác định, cũng như trong bất kỳ khối con nào được chứa. Theo cách này, hãy làm việc rất giống như var . Sự khác biệt chính là phạm vi của một biến var là toàn bộ hàm kèm theo:
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}`
Ở cấp cao nhất của chương trình và chức năng, hãy , không giống như var , không tạo ra một thuộc tính trên đối tượng toàn cầu. Ví dụ:
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
Khi được sử dụng bên trong một khối, hãy giới hạn phạm vi của biến đối với khối đó. Lưu ý sự khác biệt giữa var có phạm vi bên trong hàm nơi nó được khai báo.
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // the scope is global
let b = 22; // the scope is inside the if-block
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
Cũng đừng quên tính năng ECMA6, vì vậy nó chưa được hỗ trợ đầy đủ, vì vậy tốt hơn là luôn chuyển nó sang ECMA5 bằng Babel, v.v ... để biết thêm thông tin về việc truy cập trang web của babel
Biến không nâng
let
sẽ không nâng lên toàn bộ phạm vi của khối mà chúng xuất hiện. Ngược lại, var
có thể nâng lên như bên dưới.
{
console.log(cc); // undefined. Caused by hoisting
var cc = 23;
}
{
console.log(bb); // ReferenceError: bb is not defined
let bb = 23;
}
Trên thực tế, Per @Bergi, Cả hai var
và let
đều được nâng lên .
Thu gom rác thải
Phạm vi khối let
là hữu ích liên quan đến việc đóng cửa và thu gom rác để lấy lại bộ nhớ. Xem xét,
function process(data) {
//...
}
var hugeData = { .. };
process(hugeData);
var btn = document.getElementById("mybutton");
btn.addEventListener( "click", function click(evt){
//....
});
Cuộc click
gọi lại xử lý không cần hugeData
biến nào cả. Về mặt lý thuyết, sau khi process(..)
chạy, cấu trúc dữ liệu khổng lồ hugeData
có thể được thu gom rác. Tuy nhiên, có thể một số công cụ JS vẫn sẽ phải giữ cấu trúc khổng lồ này, vì click
chức năng này đã đóng cửa trên toàn bộ phạm vi.
Tuy nhiên, phạm vi khối có thể làm cho cấu trúc dữ liệu khổng lồ này thành rác được thu thập.
function process(data) {
//...
}
{ // anything declared inside this block can be garbage collected
let hugeData = { .. };
process(hugeData);
}
var btn = document.getElementById("mybutton");
btn.addEventListener( "click", function click(evt){
//....
});
let
vòng lặp
let
trong vòng lặp có thể liên kết lại nó với mỗi lần lặp của vòng lặp, đảm bảo gán lại cho nó giá trị từ cuối vòng lặp trước đó. Xem xét,
// print '5' 5 times
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Tuy nhiên, thay thế var
bằnglet
// print 1, 2, 3, 4, 5. now
for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Bởi vì let
tạo một môi trường từ vựng mới với các tên đó cho a) biểu thức khởi tạo b) mỗi lần lặp (chủ yếu để đánh giá biểu thức tăng), nên có thêm chi tiết ở đây .
Đây là một ví dụ để thêm vào những gì người khác đã viết. Giả sử bạn muốn tạo một mảng các hàm, adderFunctions
trong đó mỗi hàm lấy một đối số Số duy nhất và trả về tổng của đối số và chỉ mục của hàm trong mảng. Cố gắng tạo adderFunctions
vòng lặp bằng var
từ khóa sẽ không hoạt động theo cách mà ai đó có thể mong đợi một cách ngây thơ:
// An array of adder functions.
var adderFunctions = [];
for (var i = 0; i < 1000; i++) {
// We want the function at index i to add the index to its argument.
adderFunctions[i] = function(x) {
// What is i bound to here?
return x + i;
};
}
var add12 = adderFunctions[12];
// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000
// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true
Quá trình trên không tạo ra mảng chức năng mong muốn vì i
phạm vi của nó vượt ra ngoài vòng lặp của for
khối trong đó mỗi hàm được tạo. Thay vào đó, ở cuối vòng lặp, việc đóng i
trong mỗi hàm tham chiếu đến i
giá trị ở cuối vòng lặp (1000) cho mỗi hàm ẩn danh trong adderFunctions
. Đây hoàn toàn không phải là điều chúng tôi muốn: hiện tại chúng tôi có một mảng gồm 1000 chức năng khác nhau trong bộ nhớ với cùng một hành vi. Và nếu sau đó chúng tôi cập nhật giá trị của i
, đột biến sẽ ảnh hưởng đến tất cả adderFunctions
.
Tuy nhiên, chúng ta có thể thử lại bằng let
từ khóa:
// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];
for (let i = 0; i < 1000; i++) {
// NOTE: We're using the newer arrow function syntax this time, but
// using the "function(x) { ..." syntax from the previous example
// here would not change the behavior shown.
adderFunctions[i] = x => x + i;
}
const add12 = adderFunctions[12];
// Yay! The behavior is as expected.
console.log(add12(8) === 20); // => true
// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined
Lần này, i
được bật lại trên mỗi lần lặp của for
vòng lặp. Mỗi hàm hiện giữ giá trị i
tại thời điểm tạo hàm vàadderFunctions
hoạt động như mong đợi.
Bây giờ, hình ảnh trộn lẫn hai hành vi và có thể bạn sẽ thấy lý do tại sao không nên kết hợp cái mới hơn let
và const
với cái cũ hơn var
trong cùng một tập lệnh. Làm như vậy có thể dẫn đến một số mã khó hiểu ngoạn mục.
const doubleAdderFunctions = [];
for (var i = 0; i < 1000; i++) {
const j = i;
doubleAdderFunctions[i] = x => x + i + j;
}
const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];
// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true
Đừng để điều này xảy ra với bạn. Sử dụng một kẻ nói dối.
LƯU Ý: Đây là một ví dụ giảng dạy nhằm thể hiện
var
/let
hành vi trong các vòng lặp và với việc đóng chức năng cũng sẽ dễ hiểu. Đây sẽ là một cách khủng khiếp để thêm số. Nhưng kỹ thuật chung để thu thập dữ liệu trong các lần đóng chức năng ẩn danh có thể gặp phải trong thế giới thực trong các bối cảnh khác. YMMV.
let value = i;
. Câu for
lệnh tạo ra một khối từ vựng.
Sự khác biệt là trong phạm vi của các biến được khai báo với mỗi biến.
Trong thực tế, có một số hậu quả hữu ích của sự khác biệt về phạm vi:
let
các biến chỉ được nhìn thấy trong khối kèm theo gần nhất của chúng ({ ... }
).let
các biến chỉ có thể sử dụng được trong các dòng mã xảy ra sau khi biến được khai báo (mặc dù chúng được nâng lên !).let
các biến có thể không được xác định lại bởi một var
hoặc let
.let
Biến toàn cục không được thêm vào window
đối tượng toàn cầu .let
các biến rất dễ sử dụng khi đóng (chúng không gây ra tình trạng chủng tộc ).Các hạn chế được áp đặt bằng cách let
giảm khả năng hiển thị của các biến và tăng khả năng va chạm tên không mong muốn sẽ được tìm thấy sớm. Điều này giúp dễ dàng theo dõi và lý do về các biến, bao gồm khả năng tiếp cận của chúng (giúp lấy lại bộ nhớ không sử dụng).
Hậu quả là, let
các biến ít có khả năng gây ra sự cố khi được sử dụng trong các chương trình lớn hoặc khi các khung phát triển độc lập được kết hợp theo những cách mới và bất ngờ.
var
có thể vẫn hữu ích nếu bạn chắc chắn muốn có hiệu ứng liên kết đơn khi sử dụng bao đóng trong một vòng lặp (# 5) hoặc để khai báo các biến toàn cục có thể nhìn thấy bên ngoài trong mã của bạn (# 4). Việc sử dụng var
cho xuất khẩu có thể được thay thế nếu export
di chuyển ra khỏi không gian transpiler và vào ngôn ngữ cốt lõi.
1. Không sử dụng bên ngoài khối kèm theo gần nhất:
Khối mã này sẽ gây ra lỗi tham chiếu vì lần sử dụng thứ hai x
xảy ra bên ngoài khối nơi được khai báo với let
:
{
let x = 1;
}
console.log(`x is ${x}`); // ReferenceError during parsing: "x is not defined".
Ngược lại, cùng một ví dụ với var
các công trình.
2. Không sử dụng trước khi khai báo:
Khối mã này sẽ ném ReferenceError
trước khi mã có thể được chạy vì x
được sử dụng trước khi được khai báo:
{
x = x + 1; // ReferenceError during parsing: "x is not defined".
let x;
console.log(`x is ${x}`); // Never runs.
}
Ngược lại, cùng một ví dụ với các var
phân tích cú pháp và chạy mà không đưa ra bất kỳ ngoại lệ nào.
3. Không khai báo lại:
Đoạn mã sau chứng tỏ rằng một biến được khai báo có let
thể không được khai báo lại sau:
let x = 1;
let x = 2; // SyntaxError: Identifier 'x' has already been declared
4. Quả cầu không được đính kèm window
:
var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link); // OK
console.log(window.link); // undefined (GOOD!)
console.log(window.button); // OK
5. Dễ dàng sử dụng với các bao đóng:
Các biến được khai báo var
không hoạt động tốt với các bao đóng bên trong các vòng lặp. Đây là một vòng lặp đơn giản đưa ra chuỗi các giá trị mà biến i
có tại các thời điểm khác nhau:
for (let i = 0; i < 5; i++) {
console.log(`i is ${i}`), 125/*ms*/);
}
Cụ thể, kết quả này:
i is 0
i is 1
i is 2
i is 3
i is 4
Trong JavaScript, chúng tôi thường sử dụng các biến tại một thời điểm muộn hơn đáng kể so với khi chúng được tạo. Khi chúng tôi chứng minh điều này bằng cách trì hoãn đầu ra với một bao đóng được chuyển đến setTimeout
:
for (let i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
... Đầu ra vẫn không thay đổi miễn là chúng tôi gắn bó let
. Ngược lại, nếu chúng ta đã sử dụng var i
thay thế:
for (var i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
... vòng lặp bất ngờ xuất ra "i là 5" năm lần:
i is 5
i is 5
i is 5
i is 5
i is 5
var
thay vì let
, mã tương đương với: var i = 0; while (i < 5) { doSomethingLater(); i++; }
i
nằm ngoài bao đóng và theo thời gian doSomethingLater()
được thực thi, i
đã được tăng lên 5 lần, do đó đầu ra là i is 5
năm lần. Bằng cách sử dụng let
, biến i
nằm trong bao đóng, vì vậy mỗi cuộc gọi không đồng bộ sẽ có bản sao i
thay vì sử dụng 'toàn cầu' được tạo bằng var
.
for
. Một phép biến đổi chính xác hơn, mặc dù phức tạp hơn, là for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(
i cổ điển là $ {j} ), 125/*ms*/); })(i); }
, giới thiệu một "bản ghi kích hoạt chức năng" để lưu từng giá trị i
với tên của j
hàm bên trong hàm.
Có thể hai chức năng sau đây cho thấy sự khác biệt:
function varTest() {
var x = 31;
if (true) {
var x = 71; // Same variable!
console.log(x); // 71
}
console.log(x); // 71
}
function letTest() {
let x = 31;
if (true) {
let x = 71; // Different variable
console.log(x); // 71
}
console.log(x); // 31
}
let
thật thú vị, vì nó cho phép chúng ta làm một cái gì đó như thế này:
(() => {
var count = 0;
for (let i = 0; i < 2; ++i) {
for (let i = 0; i < 2; ++i) {
for (let i = 0; i < 2; ++i) {
console.log(count++);
}
}
}
})();
Mà kết quả là đếm [0, 7].
Trong khi
(() => {
var count = 0;
for (var i = 0; i < 2; ++i) {
for (var i = 0; i < 2; ++i) {
for (var i = 0; i < 2; ++i) {
console.log(count++);
}
}
}
})();
Chỉ tính [0, 1].
Sự khác biệt chính giữa var
và let
là biến khai báo với var
được chức năng scoped . Trong khi đó các hàm được khai báo let
là có phạm vi khối . Ví dụ:
function testVar () {
if(true) {
var foo = 'foo';
}
console.log(foo);
}
testVar();
// logs 'foo'
function testLet () {
if(true) {
let bar = 'bar';
}
console.log(bar);
}
testLet();
// reference error
// bar is scoped to the block of the if statement
các biến có var
:
Khi hàm đầu tiên testVar
được gọi là biến foo, được khai báo với var
, vẫn có thể truy cập được bên ngoài if
câu lệnh. Biến foo
này sẽ có sẵn ở mọi nơi trong phạm vi của testVar
hàm .
các biến có let
:
Khi hàm thứ hai testLet
được gọi là thanh biến, được khai báo bằng let
, chỉ có thể truy cập bên trong if
câu lệnh. Bởi vì các biến được khai báo let
là có phạm vi khối (trong đó một khối là mã giữa các dấu ngoặc nhọn if{}
, vd for{}
, function{}
).
let
các biến không được nâng lên:Một điểm khác biệt giữa var
và let
là các biến có khai báo let
không được nâng lên . Một ví dụ là cách tốt nhất để minh họa hành vi này:
các biến let
không được nâng lên:
console.log(letVar);
let letVar = 10;
// referenceError, the variable doesn't get hoisted
các biến với var
do được nâng lên:
console.log(varVar);
var varVar = 10;
// logs undefined, the variable gets hoisted
let
không gắn bó vớiwindow
:Một biến được khai báo let
trong phạm vi toàn cục (là mã không có trong hàm) sẽ không được thêm dưới dạng một thuộc tính trên window
đối tượng toàn cục . Ví dụ: mã này nằm trong phạm vi toàn cầu):
var bar = 5;
let foo = 10;
console.log(bar); // logs 5
console.log(foo); // logs 10
console.log(window.bar);
// logs 5, variable added to window object
console.log(window.foo);
// logs undefined, variable not added to window object
Khi nào nên
let
sử dụng hơnvar
?
Sử dụng let
hơn var
bất cứ khi nào bạn có thể bởi vì nó chỉ đơn giản là phạm vi cụ thể hơn. Điều này làm giảm xung đột đặt tên tiềm năng có thể xảy ra khi xử lý một số lượng lớn các biến. var
có thể được sử dụng khi bạn muốn một biến toàn cục rõ ràng nằm trên window
đối tượng (luôn luôn cân nhắc cẩn thận nếu điều này thực sự cần thiết).
var
là phạm vi toàn cầu (Palăng-có thể) biến.
let
và const
là phạm vi khối.
test.js
{
let l = 'let';
const c = 'const';
var v = 'var';
v2 = 'var 2';
}
console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined
Khi đang sử dụng let
Các let
từ khóa gắn việc khai báo biến với phạm vi của bất cứ khối (thường là một { .. }
cặp) nó chứa trong. Nói cách khác,let
ngầm hijacks phạm vi bất kỳ của khối khai báo biến của nó.
let
các biến không thể được truy cập trong window
đối tượng vì chúng không thể được truy cập trên toàn cầu.
function a(){
{ // this is the Max Scope for let variable
let x = 12;
}
console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined
Khi đang sử dụng var
var
và các biến trong ES5 có phạm vi trong các hàm có nghĩa là các biến có giá trị trong hàm và không nằm ngoài chính hàm đó.
var
các biến có thể được truy cập trong window
đối tượng vì chúng không thể được truy cập trên toàn cầu.
function a(){ // this is the Max Scope for var variable
{
var x = 12;
}
console.log(x);
}
a(); // 12
Nếu bạn muốn biết thêm hãy tiếp tục đọc bên dưới
một trong những câu hỏi phỏng vấn nổi tiếng nhất về phạm vi cũng có thể đủ cho việc sử dụng chính xác let
và var
như dưới đây;
Khi đang sử dụng let
for (let i = 0; i < 10 ; i++) {
setTimeout(
function a() {
console.log(i); //print 0 to 9, that is literally AWW!!!
},
100 * i);
}
Điều này là do khi sử dụng let
, với mỗi lần lặp lặp, biến được đặt trong phạm vi và có bản sao riêng.
Khi đang sử dụng var
for (var i = 0; i < 10 ; i++) {
setTimeout(
function a() {
console.log(i); //print 10 times 10
},
100 * i);
}
Điều này là do khi sử dụng var
, với mỗi lần lặp lặp, biến được đặt trong phạm vi và có bản sao được chia sẻ.
for (let i = 0; i < 5; i++) {
// i accessible ✔️
}
// i not accessible ❌
for (var i = 0; i < 5; i++) {
// i accessible ✔️
}
// i accessible ✔️
Sandbox để chơi xung quanh
Nếu tôi đọc đúng thông số kỹ thuật thì let
rất may cũng có thể được tận dụng để tránh các chức năng tự gọi được sử dụng để mô phỏng các thành viên chỉ riêng tư - một mẫu thiết kế phổ biến làm giảm khả năng đọc mã, làm phức tạp việc gỡ lỗi, không thêm bảo vệ mã thực hoặc lợi ích nào khác - ngoại trừ có thể làm hài lòng ai đó mong muốn về ngữ nghĩa, vì vậy hãy ngừng sử dụng nó. / rant
var SomeConstructor;
{
let privateScope = {};
SomeConstructor = function SomeConstructor () {
this.someProperty = "foo";
privateScope.hiddenProperty = "bar";
}
SomeConstructor.prototype.showPublic = function () {
console.log(this.someProperty); // foo
}
SomeConstructor.prototype.showPrivate = function () {
console.log(privateScope.hiddenProperty); // bar
}
}
var myInstance = new SomeConstructor();
myInstance.showPublic();
myInstance.showPrivate();
console.log(privateScope.hiddenProperty); // error
Xem ' Thi đua giao diện riêng tư '
let
không? (Tôi giả sử bạn có nghĩa là IIFE với chức năng tự gọi ra của mình.)
hiddenProperty
trong constructor? Chỉ có một hiddenProperty
cho tất cả các trường hợp trong lớp của bạn.
Một số hack với let
:
1.
let statistics = [16, 170, 10];
let [age, height, grade] = statistics;
console.log(height)
2.
let x = 120,
y = 12;
[x, y] = [y, x];
console.log(`x: ${x} y: ${y}`);
3.
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // undefined
let node = {
type: "Identifier"
};
let { type: localType, name: localName = "bar" } = node;
console.log(localType); // "Identifier"
console.log(localName); // "bar"
let
:let jar = {
numberOfCookies: 10,
get cookies() {
return this.numberOfCookies;
},
set cookies(value) {
this.numberOfCookies = value;
}
};
console.log(jar.cookies)
jar.cookies = 7;
console.log(jar.cookies)
let { type, name, value } = node;
gì? Bạn tạo một đối tượng mới với 3 thuộc tính type / name / value và khởi tạo chúng với các giá trị thuộc tính từ nút?
var
quá.
hãy để vs var. Đó là tất cả về phạm vi .
Các biến var là toàn cục và có thể được truy cập cơ bản ở mọi nơi, trong khi các biến không phải là toàn cục và chỉ tồn tại cho đến khi dấu ngoặc đơn đóng giết chúng.
Xem ví dụ của tôi dưới đây và lưu ý cách biến sư tử (let) hoạt động khác nhau trong hai console.logs; nó trở nên nằm ngoài phạm vi trong console.log thứ 2.
var cat = "cat";
let dog = "dog";
var animals = () => {
var giraffe = "giraffe";
let lion = "lion";
console.log(cat); //will print 'cat'.
console.log(dog); //will print 'dog', because dog was declared outside this function (like var cat).
console.log(giraffe); //will print 'giraffe'.
console.log(lion); //will print 'lion', as lion is within scope.
}
console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
ES6 đã giới thiệu hai từ khóa mới ( let và const ) thay thế cho var .
Khi bạn cần giảm tốc độ khối, bạn có thể sử dụng let và const thay vì var.
Bảng dưới đây tóm tắt sự khác biệt giữa var, let và const
hãy là một phần của es6. Các chức năng này sẽ giải thích sự khác biệt một cách dễ dàng.
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
Dưới đây cho thấy 'let' và 'var' khác nhau như thế nào trong phạm vi:
let gfoo = 123;
if (true) {
let gfoo = 456;
}
console.log(gfoo); // 123
var hfoo = 123;
if (true) {
var hfoo = 456;
}
console.log(hfoo); // 456
Giá trị gfoo
được xác định let
ban đầu nằm trong phạm vi toàn cầu và khi chúng ta khai báo gfoo
lại bên trong phạm viif clause
của nó thay đổi và khi một giá trị mới được gán cho biến bên trong phạm vi đó thì nó không ảnh hưởng đến phạm vi toàn cầu.
Trong khi đó hfoo
, được định nghĩa var
ban đầu là trong phạm vi toàn cầu , nhưng một lần nữa khi chúng ta khai báo nó bên trong if clause
, nó xem xét phạm vi toàn cầu hfoo, mặc dù var đã được sử dụng lại để khai báo nó. Và khi chúng ta gán lại giá trị của nó, chúng ta thấy rằng phạm vi toàn cầu hfoo cũng bị ảnh hưởng. Đây là sự khác biệt chính.
Như được đề cập ở trên:
Sự khác biệt là phạm vi.
var
được đặt trong phạm vi khối chức năng gần nhất vàlet
nằm trong khối bao quanh gần nhất , có thể nhỏ hơn khối chức năng. Cả hai đều là toàn cục nếu bên ngoài bất kỳ khối nào. Hãy xem ví dụ:
Ví dụ 1:
Trong cả hai ví dụ của tôi, tôi có một chức năng myfunc
. myfunc
chứa một biến myvar
bằng 10. Trong ví dụ đầu tiên của tôi, tôi kiểm tra xem có myvar
bằng 10 ( myvar==10
) không. Nếu có, tôi agian khai báo một biến myvar
(bây giờ tôi có hai biến myvar) bằng cách sử dụng var
từ khóa và gán cho nó một giá trị mới (20). Trong dòng tiếp theo tôi in giá trị của nó trên bàn điều khiển của tôi. Sau khối điều kiện tôi lại in giá trị myvar
trên bảng điều khiển của mình. Nếu bạn nhìn vào đầu ra của myfunc
, myvar
có giá trị bằng 20.
Ví dụ2:
Trong ví dụ thứ hai của tôi thay vì sử dụng var
từ khóa trong khối điều kiện của tôi, tôi khai báo myvar
bằng let
từ khóa. Bây giờ khi tôi gọi myfunc
tôi nhận được hai đầu ra khác nhau: myvar=20
và myvar=10
.
Vì vậy, sự khác biệt là rất đơn giản tức là phạm vi của nó.
Tôi muốn liên kết các từ khóa này với Bối cảnh thực thi, bởi vì Bối cảnh thực thi là quan trọng trong tất cả những điều này. Bối cảnh thực thi có hai giai đoạn: Giai đoạn sáng tạo và giai đoạn thực thi. Ngoài ra, mỗi Bối cảnh thực thi có Môi trường biến đổi và Môi trường bên ngoài (Môi trường từ điển).
Trong Giai đoạn tạo của bối cảnh thực thi, var, let và const vẫn sẽ lưu trữ biến của nó trong bộ nhớ với giá trị không xác định trong Môi trường biến đổi của bối cảnh thực thi đã cho. Sự khác biệt là trong Giai đoạn thực thi. Nếu bạn sử dụng tham chiếu một biến được xác định bằng var trước khi nó được gán một giá trị, nó sẽ không được xác định. Không có ngoại lệ sẽ được nâng lên.
Tuy nhiên, bạn không thể tham chiếu biến được khai báo bằng let hoặc const cho đến khi nó được khai báo. Nếu bạn cố gắng sử dụng nó trước khi nó được khai báo, thì một ngoại lệ sẽ được nêu ra trong Giai đoạn thực thi của bối cảnh thực thi. Bây giờ biến vẫn sẽ nằm trong bộ nhớ, nhờ vào Giai đoạn tạo của bối cảnh thực thi, nhưng Công cụ sẽ không cho phép bạn sử dụng nó:
function a(){
b;
let b;
}
a();
> Uncaught ReferenceError: b is not defined
Với một biến được xác định bằng var, nếu Engine không thể tìm thấy biến trong Môi trường biến đổi của bối cảnh thực thi hiện tại, thì nó sẽ đi lên chuỗi phạm vi (Môi trường bên ngoài) và kiểm tra biến môi trường ngoài của môi trường bên ngoài để tìm biến. Nếu nó không thể tìm thấy nó ở đó, nó sẽ tiếp tục tìm kiếm Chuỗi phạm vi. Đây không phải là trường hợp với let và const.
Tính năng thứ hai của let là nó giới thiệu phạm vi khối. Các khối được xác định bởi dấu ngoặc nhọn. Ví dụ bao gồm các khối chức năng, nếu các khối, cho các khối, v.v. Khi bạn khai báo một biến với bên trong một khối, biến đó chỉ có sẵn bên trong khối. Trong thực tế, mỗi khi khối được chạy, chẳng hạn như trong vòng lặp for, nó sẽ tạo ra một biến mới trong bộ nhớ.
ES6 cũng giới thiệu từ khóa const để khai báo các biến. const cũng là khối phạm vi. Sự khác biệt giữa let và const là các biến const cần được khai báo bằng bộ khởi tạo, hoặc nó sẽ tạo ra lỗi.
Và cuối cùng, khi nói đến Bối cảnh thực thi, các biến được xác định bằng var sẽ được gắn vào đối tượng 'this'. Trong bối cảnh thực thi toàn cầu, đó sẽ là đối tượng cửa sổ trong các trình duyệt. Đây không phải là trường hợp cho phép hoặc const.
Tôi nghĩ rằng các điều khoản và hầu hết các ví dụ là một chút áp đảo, Vấn đề chính tôi có cá nhân với sự khác biệt là hiểu "Khối" là gì. Tại một số điểm tôi nhận ra, một khối sẽ là bất kỳ dấu ngoặc nhọn nào ngoại trừ IF
câu lệnh. một khung mở {
của hàm hoặc vòng lặp sẽ xác định một khối mới, bất cứ thứ gì được xác định let
bên trong nó, sẽ không có sẵn sau dấu ngoặc đóng }
của cùng một thứ (hàm hoặc vòng lặp); Với ý nghĩ đó, nó dễ hiểu hơn:
let msg = "Hello World";
function doWork() { // msg will be available since it was defined above this opening bracket!
let friends = 0;
console.log(msg);
// with VAR though:
for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
console.log(iCount2);
for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
console.log(iCount1);
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);
Bây giờ tôi nghĩ rằng có một phạm vi biến tốt hơn cho một khối các câu lệnh bằng cách sử dụng let
:
function printnums()
{
// i is not accessible here
for(let i = 0; i <10; i+=)
{
console.log(i);
}
// i is not accessible here
// j is accessible here
for(var j = 0; j <10; j++)
{
console.log(j);
}
// j is accessible here
}
Tôi nghĩ mọi người sẽ bắt đầu sử dụng let here sau đó để họ có phạm vi tương tự trong JavaScript như các ngôn ngữ khác, Java, C #, v.v.
Những người không hiểu rõ về phạm vi trong JavaScript được sử dụng để mắc lỗi trước đó.
Tời kéo không được hỗ trợ sử dụng let
.
Với cách tiếp cận này, lỗi trong JavaScript đang được loại bỏ.
Tham khảo ES6 In Depth: let and const để hiểu rõ hơn về nó.
Bài viết này xác định rõ sự khác biệt giữa var, let và const
const
là một tín hiệu cho thấy định danh sẽ không được gán lại.
let
, là tín hiệu cho thấy biến có thể được gán lại, chẳng hạn như bộ đếm trong vòng lặp hoặc hoán đổi giá trị trong thuật toán. Nó cũng báo hiệu rằng biến sẽ chỉ được sử dụng trong khối được xác định trong đó, không phải lúc nào cũng là toàn bộ hàm chứa.
var
bây giờ là tín hiệu yếu nhất có sẵn khi bạn xác định một biến trong JavaScript. Biến có thể được hoặc không được gán lại và biến có thể được sử dụng cho toàn bộ hàm hoặc chỉ cho mục đích của một khối hoặc vòng lặp.
https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b
let
được bao gồm trong dự thảo phiên bản thứ 6 và rất có thể sẽ nằm trong đặc điểm kỹ thuật cuối cùng.