What's the difference between using “let” and “var”?
ecmascript 6引入了
我听说它被描述为一个"局部"变量,但我仍然不确定它的行为与
有什么区别?
区别在于范围。
另外,使用
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | var html = ''; write('#### global #### '); write('globalVar: ' + globalVar); //undefined, but visible try { write('globalLet: ' + globalLet); //undefined, *not* visible } catch (exception) { write('globalLet: exception'); } write(' set variables'); var globalVar = 'globalVar'; let globalLet = 'globalLet'; write(' globalVar: ' + globalVar); write('globalLet: ' + globalLet); function functionScoped() { write(' #### function ####'); write(' functionVar: ' + functionVar); //undefined, but visible try { write('functionLet: ' + functionLet); //undefined, *not* visible } catch (exception) { write('functionLet: exception'); } write(' set variables'); var functionVar = 'functionVar'; let functionLet = 'functionLet'; write(' functionVar: ' + functionVar); write('functionLet: ' + functionLet); } function blockScoped() { write(' #### block ####'); write(' blockVar: ' + 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(' blockVar: ' + blockVar); // visible here and whole function }; for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) { write('blockLet: ' + blockLet); // visible only here }; write(' blockVar: ' + 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; |
1 | [cc lang="javascript"] |
.
1 2 | </P>全球的:<P>当在函数块外这样使用时,它们非常相似。</P>[cc lang="javascript"]let me = 'go'; // globally scoped var i = 'able'; // globally scoped |
但是,用
1 2 | console.log(window.me); // undefined console.log(window.i); // 'able' |
功能:
当在函数块中这样使用时,它们是相同的。
1 2 3 4 | function ingWithinEstablishedParameters() { let terOfRecommendation = 'awesome worker!'; //function block scoped var sityCheerleading = 'go!'; //function block scoped } |
Block:
这就是区别。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 } |
Redeclaration:
假设使用严格模式,
1 2 3 | 'use strict'; let me = 'foo'; let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared |
1 2 3 | 'use strict'; var me = 'foo'; var me = 'bar'; // No problem, `me` is replaced. |
也可以使用
演示
1 2 3 4 | for(var i = 1; i < 6; i++) { document.getElementById('my-element' + i) .addEventListener('click', function() { alert(i) }) } |
上面的代码演示了一个典型的JavaScript关闭问题。对
每个单击处理程序都将引用同一个对象,因为只有一个计数器对象可容纳6个对象,所以每次单击都有6个对象。
一般的解决方法是将其包装在一个匿名函数中,并将
演示(在Chrome和Firefox 50中测试)
1 2 3 4 5 6 | 'use strict'; for(let i = 1; i < 6; i++) { document.getElementById('my-element' + i) .addEventListener('click', function() { alert(i) }) } |
下面是对
let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function
维基百科上的这个表显示了哪些浏览器支持JavaScript1.7。
请注意,只有Mozilla和Chrome浏览器支持它。也就是说,Safari和其他潜在的公司没有。
- 使用
var 语句定义的变量从函数开始就在定义它的整个函数中都是已知的。(*) - 使用
let 语句定义的变量只在定义它的块中知道,从定义它开始。(**)
要了解差异,请考虑以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | // 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 |
在这里,我们可以看到我们的变量
另外,考虑块范围变量在声明之前是未知的,因为它们没有被提升。也不允许在同一个块中重新声明相同的块范围变量。这使得块范围变量比全局或功能范围变量更不容易出错,这些变量被提升,并且在多个声明时不会产生任何错误。
今天使用有些人会争辩说,将来我们只使用let语句,而var语句将变得过时。JavaScript专家凯尔·辛普森写了一篇非常详细的文章,阐述了为什么他认为情况并非如此。
然而,今天肯定不是这样。实际上,我们需要问问自己使用
如果您正在编写服务器端的javascript代码(node.js),那么可以安全地使用
let 语句。如果您正在编写客户端JavaScript代码并使用基于浏览器的蒸腾器(如tracer或babel standalone),则可以安全地使用
let 语句,但是您的代码在性能方面可能不是最佳的。如果您正在编写客户端JavaScript代码并使用基于节点的蒸腾器(如tracer shell脚本或babel),则可以安全地使用
let 语句。而且,因为您的浏览器只知道所发生的代码,所以性能缺陷应该是有限的。如果您正在编写客户端JavaScript代码,并且不使用蒸腾器,那么您需要考虑浏览器支持。
还有一些浏览器根本不支持
let :
有关阅读此答案时哪些浏览器支持
(*)全局和功能范围的变量可以在声明之前初始化和使用,因为JavaScript变量被提升。这意味着声明总是位于范围的顶部。
(**)未提升块范围变量
接受的答案缺少一点:
1 2 3 4 5 | { let a = 123; }; console.log(a); // ReferenceError: a is not defined |
使用
在顶层,使用
1 2 3 4 5 6 7 8 | var globalVariable = 42; let blockScopedVariable = 43; console.log(globalVariable); // 42 console.log(blockScopedVariable); // 43 console.log(this.globalVariable); // 42 console.log(this.blockScopedVariable); // undefined |
函数内部
在函数内部(但在块外部),
1 2 3 4 5 6 7 8 9 10 | (() => { 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 |
街区内
在块内使用
1 2 3 4 5 6 7 8 9 | { 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 |
环内
循环中使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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. |
带闭包的回路
如果在循环中使用
1 2 3 4 5 6 7 8 9 | // 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); } |
时间死区
由于时间死区的原因,使用
1 2 3 4 | console.log(noTDZ); // undefined var noTDZ = 43; console.log(hasTDZ); // ReferenceError: hasTDZ is not defined let hasTDZ = 42; |
不重新声明
不能使用
1 2 3 4 5 6 7 8 | 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 |
不能重新分配使用
1 2 | const a = 42; a = 43; // TypeError: Assignment to constant variable. |
注意,这并不意味着值是不可变的。它的属性仍然可以更改。
1 2 3 | const obj = {}; obj.a = 42; console.log(obj.a); // 42 |
如果你想要一个不变的对象,你应该使用
使用
1 | const a; // SyntaxError: Missing initializer in const declaration |
有一些细微的区别——
例如,它作用于封闭块,它们在声明之前不存在,等等。
但是值得注意的是,
下面是这两者之间的区别示例(对chrome的支持刚刚开始):
如您所见,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | "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); |
variable not liftingEDOCX1[0]不会提升到它们出现的块的整个范围。相比之下,var 可以提升如下。1
2
3
4
5
6
7
8
9{
console.log(cc); // undefined. Caused by hoisting
var cc = 23;
}
{
console.log(bb); // ReferenceError: bb is not defined
let bb = 23;
}实际上,在Per@Bergi,
var 和let 都被提升。垃圾收集
let 的块范围对于闭包和回收内存的垃圾收集很有用。考虑一下,1
2
3
4
5
6
7
8
9
10
11
12function process(data) {
//...
}
var hugeData = { .. };
process(hugeData);
var btn = document.getElementById("mybutton");
btn.addEventListener("click", function click(evt){
//....
});click 处理程序回调根本不需要hugeData 变量。从理论上讲,在process(..) 运行后,巨大的数据结构hugeData 可能被垃圾收集。但是,由于click 函数在整个范围内都有一个闭包,因此一些JS引擎可能仍然需要保持这个巨大的结构。但是,块作用域可以使这个巨大的数据结构被垃圾收集。
1
2
3
4
5
6
7
8
9
10
11
12
13function 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 循环循环中的
let 可以将其重新绑定到循环的每个迭代,确保从上一个循环迭代结束时重新为其赋值。考虑一下,1
2
3
4
5
6// print '5' 5 times
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}但是,用
let 替换var 。1
2
3
4
5
6// print 1, 2, 3, 4, 5. now
for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}因为
let 为a)初始化器表达式b)每次迭代(预先计算增量表达式)创建了一个新的词汇环境,所以这里有更多的细节。
主要的区别是范围差异,而let只能在声明的范围内使用,比如for循环,var可以在循环外访问。来自MDN中的文档(也来自MDN的示例):
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.
Variables declared by let have as their scope the block in which they are defined, as well as in any contained sub-blocks. In this way, let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 }` |
At the top level of programs and functions, let, unlike var, does not create a property on the global object. For example:
1 2 3 4 | var x = 'global'; let y = 'global'; console.log(this.x); //"global" console.log(this.y); // undefined |
When used inside a block, let limits the variable's scope to that block. Note the difference between var whose scope is inside the function where it is declared.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
也不要忘记它的ecma6特性,所以它还没有完全支持,所以最好总是使用babel等将它发到ecma5。有关访问Babel网站的更多信息
下面是一个例子来补充其他人已经写过的内容。假设您想要创建一个函数数组,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 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 |
上述过程不会生成所需的函数数组,因为
但是,我们可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 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 |
这一次,
现在,图像混合这两种行为,您可能会看到为什么不建议在同一脚本中混合较新的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 |
别让这件事发生在你身上。使用棉绒。
NOTE: This is a teaching example intended to demonstrate the
var /let behavior in loops and with function closures that would also be easy to understand. This would be a terrible way to add numbers. But the general technique of capturing data in anonymous function closures might be encountered in the real world in other contexts. YMMV.
差异在每个变量声明的范围内。
在实践中,范围差异有许多有用的后果:
因此,当在大型程序中使用或以新的和意外的方式组合独立开发的框架时,
如果在循环中使用闭包(5)或在代码中声明外部可见的全局变量(4)时确实需要单一绑定效果,那么
1。最近的封闭块外禁止使用:此代码块将引发引用错误,因为第二次使用
1 2 3 4 | { let x = 1; } console.log(`x is ${x}`); // ReferenceError during parsing:"x is not defined". |
相比之下,使用
2。申报前不得使用:此代码块将在代码运行之前抛出一个
1 2 3 4 5 | { x = x + 1; // ReferenceError during parsing:"x is not defined". let x; console.log(`x is ${x}`); // Never runs. } |
相反,同一个使用
三。无重新声明:下面的代码演示了使用
1 2 | let x = 1; let x = 2; // SyntaxError: Identifier 'x' has already been declared |
4。不附于
1 2 3 4 5 | 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。使用方便,带封口:使用
1 2 3 | for (let i = 0; i < 5; i++) { console.log(`i is ${i}`), 125/*ms*/); } |
具体来说,该输出:
1 2 3 4 5 | i is 0 i is 1 i is 2 i is 3 i is 4 |
在JavaScript中,我们经常在比创建变量晚得多的时间使用变量。当我们通过延迟传递给
1 2 3 | for (let i = 0; i < 5; i++) { setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/); } |
…只要我们坚持使用
1 2 3 | for (var i = 0; i < 5; i++) { setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/); } |
…循环意外输出"i is 5"五次:
1 2 3 4 5 | i is 5 i is 5 i is 5 i is 5 i is 5 |
1 2 3 4 5 6 7 8 9 10 11 | (() => { 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++); } } } })(); |
从而导致计数[0,7]。
反之
1 2 3 4 5 6 7 8 9 10 11 | (() => { 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++); } } } })(); |
只计算[0,1]。
以下两个功能是否会显示不同之处:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } |
函数与块范围:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 |
当第一个函数
带
当第二个函数
带有
1 2 3 4 | console.log(letVar); let letVar = 10; // referenceError, the variable doesn't get hoisted |
带有
1 2 3 4 | console.log(varVar); var varVar = 10; // logs undefined, the variable gets hoisted |
全球
在全局范围(即不在函数中的代码)中使用
1 2 3 4 5 6 7 8 9 10 11 | 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 |
When should
let be used overvar ?
尽可能在
看起来,至少在Visual Studio 2015中,typescript 1.5中,"var"允许在一个块中声明多个相同变量名,"let"不允许。
这不会生成编译错误:
1 2 | var x = 1; var x = 2; |
这将:
1 2 | let x = 1; let x = 2; |
使用
在
1 2 3 4 5 6 7 | function a(){ { // this is the Max Scope for let variable let x = 12; } console.log(x); } a(); // Uncaught ReferenceError: x is not defined |
使用
1 2 3 4 5 6 7 | function a(){ // this is the Max Scope for var variable { var x = 12; } console.log(x); } a(); // 12 |
如果你想知道更多,继续阅读下面的内容
其中一个最著名的范围访谈问题也可以满足以下对
使用
1 2 3 4 5 6 7 | for (let i = 0; i < 10 ; i++) { setTimeout( function a() { console.log(i); //print 0 to 9, that is literally AWW!!! }, 100 * i); } |
这是因为当使用
使用
1 2 3 4 5 6 7 | for (var i = 0; i < 10 ; i++) { setTimeout( function a() { console.log(i); //print 10 times 10 }, 100 * i); } |
这是因为当使用
test.js
1 2 3 4 5 6 7 8 9 10 11 | { 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 |
如果我正确地阅读了规范,那么很幸运的是,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 |
参见"仿真专用接口"
一些使用
1。
1 2 3 4 | let statistics = [16, 170, 10]; let [age, height, grade] = statistics; console.log(height) |
2。
1 2 3 4 | let x = 120, y = 12; [x, y] = [y, x]; console.log(`x: ${x} y: ${y}`); |
三。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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" |
带
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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) |
让我们成为ES6的一部分。这些函数将以简单的方式解释差异。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } |
现在我认为使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 } |
我认为人们将开始使用"让"在这里,这样他们将在JavaScript中与其他语言、爪哇、C等类似。
对于javascript中的作用域理解不清楚的人以前常常犯错误。
使用
使用这种方法,JavaScript中出现的错误将被删除。
深入参考ES6:让和const更好地理解它。
以前,Javascript中只有两个作用域,即函数作用域和全局作用域。使用"
要完全理解"let"关键字,es6:javascript中声明变量的"let"关键字将有所帮助。
本文清楚地定义了var、let和const之间的区别。
const is a signal that the identifier won’t be reassigned.
let , is a signal that the variable may be reassigned, such as a
counter in a loop, or a value swap in an algorithm. It also signals
that the variable will be used only in the block it’s defined in,
which is not always the entire containing function.
var is now the weakest signal available when you define a variable
in JavaScript. The variable may or may not be reassigned, and the
variable may or may not be used for an entire function, or just for
the purpose of a block or loop.
https://medium.com/javascript scene/javascript-es6-var-let-or-const-ba58b8dcde75.esmkpbg9b
如上所述:
The difference is scoping.
var is scoped to the nearest function
block andlet is scoped to the nearest enclosing block, which
can be smaller than a function block. Both are global if outside any
block.Lets see an example:
实例1:
在我的两个例子中,我都有一个函数
实例2:在第二个示例中,我使用
所以区别很简单,也就是范围。
让我们对比变量,这都是关于范围的。
var变量是全局变量,基本上可以在任何地方访问,而let变量不是全局变量,只存在于右括号杀死它们之前。
请参阅下面的示例,并注意lion(let)变量在两个console.log中的行为是如何不同的;它在第二个console.log中超出了范围。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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. |
看看这张图片,我创建了一个非常简单的示例来演示
首先我们声明
由于我目前正试图深入了解JavaScript,我将分享我的简短研究,其中包含一些已经讨论过的伟大的部分,以及其他不同角度的细节。
如果我们理解函数和块范围之间的区别,那么理解var和let之间的区别就容易了。
让我们考虑以下情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | (function timer() { for(var i = 0; i <= 5; i++) { setTimeout(function notime() { console.log(i); }, i * 1000); } })(); Stack VariableEnvironment //one VariablEnvironment for timer(); // when the timer is out - the value will be the same value for each call 5. [setTimeout, i] [i=5] 4. [setTimeout, i] 3. [setTimeout, i] 2. [setTimeout, i] 1. [setTimeout, i] 0. [setTimeout, i] #################### (function timer() { for (let i = 0; i <= 5; i++) { setTimeout(function notime() { console.log(i); }, i * 1000); } })(); Stack LexicalEnvironment - each iteration has a new lexical environment 5. [setTimeout, i] [i=5] LexicalEnvironment 4. [setTimeout, i] [i=4] LexicalEnvironment 3. [setTimeout, i] [i=3] LexicalEnvironment 2. [setTimeout, i] [i=2] LexicalEnvironment 1. [setTimeout, i] [i=1] LexicalEnvironment 0. [setTimeout, i] [i=0] |
当调用
一个简单的例子
功能范围
1 2 3 4 5 6 | function test() { for(var z = 0; z < 69; z++) { //todo } //z is visible outside the loop } |
块范围
1 2 3 4 5 6 | function test() { for(var z = 0; z < 69; z++) { //todo } //z is not defined :( } |
ECMAScript 6又添加了一个关键字来声明变量"const"而不是"let"。
在"var"之上引入"let"和"const"的主要目标是使用块范围界定,而不是传统的词汇范围界定。本文简要解释了"var"和"let"的区别,并讨论了"const"的含义。
签入此链接多媒体数字网
1 2 3 4 5 6 7 8 9 10 11 | let x = 1; if (x === 1) { let x = 2; console.log(x); // expected output: 2 } console.log(x); // expected output: 1 |
我想将这些关键字链接到执行上下文,因为执行上下文在所有这一切中都很重要。执行上下文有两个阶段:创建阶段和执行阶段。此外,每个执行上下文都有一个可变的环境和外部环境(它的词汇环境)。
在执行上下文的创建阶段,var、let和const仍将其变量存储在内存中,在给定执行上下文的变量环境中具有未定义的值。区别在于执行阶段。如果在给变量赋值之前使用一个用var定义的变量引用,它将只是未定义的。不会引发异常。
但是,在声明变量之前,不能引用用let或const声明的变量。如果在声明之前尝试使用它,那么在执行上下文的执行阶段将引发异常。现在变量仍将在内存中,这取决于执行上下文的创建阶段,但引擎不允许您使用它:
1 2 3 4 5 6 | function a(){ b; let b; } a(); > Uncaught ReferenceError: b is not defined |
对于用var定义的变量,如果引擎在当前执行上下文的变量环境中找不到该变量,那么它将进入作用域链(外部环境)并检查外部环境的变量环境。如果在那里找不到它,它将继续搜索范围链。这不是let和const的情况。
let的第二个特性是它引入了块范围。块由大括号定义。示例包括函数块、if块、for块等。当用let在块内声明变量时,该变量仅在块内可用。实际上,每次运行块时,例如在for循环中,它都会在内存中创建一个新的变量。
ES6还引入了用于声明变量的const关键字。const也是块范围的。let和const的区别在于const变量需要使用初始值设定项声明,否则将生成错误。
最后,当涉及到执行上下文时,用var定义的变量将附加到"this"对象。在全局执行上下文中,这将是浏览器中的窗口对象。这不是let或const的情况。