let和var区别
var a = [];
for(var i = 0;i<10;i++){
a[i] = function(){console.log(i);};
}
a[6]();//10
var b = [];
for(let j = 0;j<10;j++){
a[j] = function(){console.log(j);};
}
a[5]();//5
第一个var中变量i,在全局范围内有效,所以全局只有一个变量i,每次循环i的值都会发生改变,而循环内被赋值给数组a的函数内部的console.log(i);里面的i指向的就是全局的i。所有数组a的成员里边的i都是同一个i;导致运行时输出的是最后一轮的i值也就是10;
第二个let中变量i,当前的i只在本轮循环中有效,所以每次循环的i其实都是一个新的变量,所以最后的输出为6.(虽然每次i都是重新声明的,但是js引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环基础上进行计算)
另外for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for(let i = 0;i<3;i++){
let i = '123'
console.log(i);
}
//123
//123
//123
var命令会发生_变量提升_现象,即变量可以在声明之前使用,值为undefined, 而let则会报错
console.log(a);//undefined
var a = 2;
"暂时性死区"(temporal dead zone,简称TDZ) 如果在区域块中存在let和const命令,这个区块对这些命令声明的变量从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量就会报错。 只要块级作用域内存在let命令,他所声明的变量就绑定这个区域,不再受外部影响。
var str = 123;
if(true){
str = 'abc';//ReferenceError
let str;
}
代码中存在全局变量str,但是块级作用域内let又声明了一个局部变量str,导致后者绑定这个块级作用域,所以在let声明变量之前对str赋值会报错。
(function foo(x=y,y=2){
return[x,y];
})();//报错
因为参数x默认等于另一个参数y,而此时y还没有声明,属于‘死区’。
ES5只有全局作用域和函数作用域,没有块级作用域导致一些错误的产生
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
变量提升导致内层的tmp变量覆盖了外层的tmp变量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
i泄露成了全局变量