ECMAScript 6介绍 该 let
声明。我听说它被描述为一个“本地”变量,但我仍然不太确定它的行为方式与它有什么不同 var
关键词。
有什么区别?什么时候应该 let
被用完了 var
?
ECMAScript 6介绍 该 let
声明。我听说它被描述为一个“本地”变量,但我仍然不太确定它的行为方式与它有什么不同 var
关键词。
有什么区别?什么时候应该 let
被用完了 var
?
区别在于范围界定。 var
范围限定到最近的功能块和 let
范围是最近的 封闭 块,可以小于功能块。如果在任何区域之外,两者都是全球
另外,用变量声明的变量 let
在它们的封闭区域中声明之前是不可访问的。如演示中所示,这将引发ReferenceError异常。
演示:
var html = '';
write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible
try {
write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
write('globalLet: exception');
}
write('\nset variables');
var globalVar = 'globalVar';
let globalLet = 'globalLet';
write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);
function functionScoped() {
write('\n#### function ####');
write('\nfunctionVar: ' + functionVar); //undefined, but visible
try {
write('functionLet: ' + functionLet); //undefined, *not* visible
} catch (exception) {
write('functionLet: exception');
}
write('\nset variables');
var functionVar = 'functionVar';
let functionLet = 'functionLet';
write('\nfunctionVar: ' + functionVar);
write('functionLet: ' + functionLet);
}
function blockScoped() {
write('\n#### block ####');
write('\nblockVar: ' + blockVar); //undefined, but visible
try {
write('blockLet: ' + blockLet); //undefined, *not* visible
} catch (exception) {
write('blockLet: exception');
}
for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
write('\nblockVar: ' + blockVar); // visible here and whole function
};
for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
write('blockLet: ' + blockLet); // visible only here
};
write('\nblockVar: ' + blockVar);
try {
write('blockLet: ' + blockLet); //undefined, *not* visible
} catch (exception) {
write('blockLet: exception');
}
}
function write(line) {
html += (line ? line : '') + '<br />';
}
functionScoped();
blockScoped();
document.getElementById('results').innerHTML = html;
<pre id="results"></pre>
在功能块之外使用它们非常相似。
let me = 'go'; // globally scoped
var i = 'able'; // globally scoped
但是,全局变量定义了 let
不会作为全局属性添加 window
像那些定义的对象 var
。
console.log(window.me); // undefined
console.log(window.i); // 'able'
在功能块中使用时它们是相同的。
function ingWithinEstablishedParameters() {
let terOfRecommendation = 'awesome worker!'; //function block scoped
var sityCheerleading = 'go!'; //function block scoped
}
这是区别。 let
只有在 for()
循环和 var
是整个功能可见的。
function allyIlliterate() {
//tuce is *not* visible out here
for( let tuce = 0; tuce < 5; tuce++ ) {
//tuce is only visible in here (and in the for() parentheses)
//and there is a separate tuce variable for each iteration of the loop
}
//tuce is *not* visible out here
}
function byE40() {
//nish *is* visible out here
for( var nish = 0; nish < 5; nish++ ) {
//nish is visible to the whole function
}
//nish *is* visible out here
}
假设严格的模式, var
将允许您在同一范围内重新声明相同的变量。另一方面, let
将不会:
'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
let
也可用于避免闭包问题。它绑定了新的价值,而不是保留旧的参考,如下面的例子所示。
for(var i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
上面的代码演示了一个典型的JavaScript闭包问题参考 i
变量存储在单击处理程序闭包中,而不是实际值 i
。
每个单击处理程序都将引用同一个对象,因为只有一个计数器对象可以容纳6,因此每次单击时会得到6个。
一般的解决方法是将其包装在匿名函数中并传递 i
作为论点。现在也可以通过使用来避免这些问题 let
代替 var
如下面的代码所示。
DEMO (在Chrome和Firefox 50中测试过)
'use strict';
for(let i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
这是一个 解释 let
关键词 举一些例子。
让我的工作非常像var。主要区别在于var变量的范围是整个封闭函数
这张桌子 在Wikipedia上显示哪些浏览器支持Javascript 1.7。
请注意,只有Mozilla和Chrome浏览器支持它。 IE,Safari和其他人可能没有。
let
和 var
?要了解其中的差异,请考虑以下代码:
// 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
在这里,我们可以看到我们的变量 j
只在第一个for循环中知道,但不在之前和之后。然而,我们的变量 i
在整个功能中都是众所周知的。
另外,请考虑块范围变量在声明之前是未知的,因为它们没有被提升。您也不允许在同一个块中重新声明相同的块范围变量。这使得块范围变量比全局或功能范围变量更不容易出错,这些变量被提升并且在多个声明的情况下不会产生任何错误。
let
今天?有些人会争辩说,将来我们只会使用let语句,而var语句将会过时。 JavaScript大师 凯尔辛普森 写 一篇非常精细的文章,说明为什么不是这样。
然而,今天绝对不是这样。事实上,我们实际上需要问自己,使用它是否安全 let
声明。这个问题的答案取决于您的环境:
如果您正在编写服务器端JavaScript代码(Node.js的),你可以安全地使用 let
声明。
如果您正在编写客户端JavaScript代码并使用转换器(如 Traceur),你可以安全地使用 let
声明,但是你的代码在性能方面可能不是最优的。
如果您正在编写客户端JavaScript代码而不使用转换器,则需要考虑浏览器支持。
今天,2018年6月8日,仍然有一些浏览器不支持 let
!
有关哪些浏览器支持的最新概述 let
在您阅读此答案时的陈述,请参阅 这个 Can I Use
页。
(*)全局和功能范围的变量可以在声明之前初始化和使用,因为JavaScript变量是 悬挂。 这意味着声明始终位于范围的顶部。
(**)未提升块范围变量
接受的答案缺少一点:
{
let a = 123;
};
console.log(a); // ReferenceError: a is not defined
有一些微妙的差异 - let
范围界定的行为更像是变量范围,或多或少任何其他语言。
例如它适用于封闭块,它们在声明之前不存在,等等。
但值得注意的是 let
只是较新的Javascript实现的一部分,并具有不同程度的 浏览器支持。
以下是两者之间差异的示例(支持刚启动的chrome):
正如你所看到的那样 var j
变量仍然具有for循环范围之外的值(块范围),但是 let i
变量在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);
let
用变量声明的变量 let
关键字是块范围的,这意味着它们仅在 块 他们被宣布。
在顶层,使用声明的变量 let
不要在全局对象上创建属性。
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined
在一个功能区内(但在一个区域外), let
与...具有相同的范围 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
使用声明的变量 let
块内部无法访问该块内部。
{
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
用变量声明的变量 let
in循环只能在该循环内引用。
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.
如果你使用 let
代替 var
在循环中,每次迭代都会得到一个新变量。这意味着您可以安全地在循环内使用闭包。
// 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);
}
因为 时间死区,变量声明使用 let
在声明它们之前无法访问。尝试这样做会引发错误。
console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;
您不能多次声明相同的变量 let
。您也无法使用声明变量 let
与使用声明的另一个变量具有相同的标识符 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
非常相似 let
-it是块范围的并且有TDZ。然而,有两件事是不同的。
变量声明使用 const
无法重新分配。
const a = 42;
a = 43; // TypeError: Assignment to constant variable.
请注意,这并不意味着该值是不可变的。它的属性仍然可以改变。
const obj = {};
obj.a = 42;
console.log(obj.a); // 42
如果你想拥有一个不可变对象,你应该使用 Object.freeze()
。
在使用声明变量时,始终必须指定一个值 const
。
const a; // SyntaxError: Missing initializer in const declaration