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]();
}
在 for 循环中,如果用 var 去定义 i ,输出的结果是一样的,而如果用的是 let ,输出则是符合直觉的 1, 2, 3 。
作用域规则
var
定义的变量在函数作用域
内有效let
定义的变量在块级作用域
内有效一个很经典的场景:
在 for 循环中,如果用
var
去定义i
,输出的结果是一样的,而如果用的是let
,输出则是符合直觉的1, 2, 3
。来具体分析一下,上面这段代码,假设不是在函数中执行的,就是打开浏览器控制台复制粘贴进去执行,所以是在
全局作用域
中执行的。而
var i = 0
这个操作,是在全局作用域
中定义的,因此i
就是个全局变量了。 所以在执行函数的时候,函数内的作用域没找到i
,因此到全局作用域中去找,所以输出的结果都是i
最后被赋的值。而i
因为是个全局变量,所以在 for 循环后依然能被访问到。如果用的
let
,则i
是被定义在 for 循环的这个块中,因此在执行函数的时候,在函数作用域中没找到,转而去上一层的块级作用域中找。而在 for 循环结束后,i
也没法被访问了,如果执行后试图输入i
,会报ReferenceError
,因为i
并没有在全局作用域中定义。变量提升
var
声明的变量会被 “提升”上述代码中,
foo
变量在函数中声明了,因为变量提升,在语句之前是一个声明了但未赋值的状态,所以第一个console.log
输出undefined
。对应使用
let
的情况:在初始化之前访问
let
声明的变量时,变量处于一个暂时死区
,即还没声明也没有赋值,因此会报ReferenceError
。全局对象属性
在全局作用域中,
let
声明的变量不会被挂到全局对象上重复声明
var
允许重复声明,后面声明的赋值会覆盖前面let
重复声明变量时会报SyntaxError
参考
Stack Overflow