从for循环看let和var的区别
MDN的let:
let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。在 ECMAScript 2015 中,let 绑定不受变量提升的约束,这意味着 let 声明不会被提升到当前执行上下文的顶部。在块中的变量初始化之前,引用它将会导致 ReferenceError(而使用 var 声明变量则恰恰相反,该变量的值是 undefined )。这个变量处于从块开始到 let 初始化处理的”暂存死区“之中。
循环定义中的let作用域:循环体中是可以引用在for声明时用let定义的变量,尽管let不是出现在大括号之间.
var list = document.getElementById("list");
for (let i = 1; i <= 5; i++) {
var item = document.createElement("LI");
item.appendChild(document.createTextNode("Item " + i));
let j = i;
item.onclick = function (ev) {
console.log("Item " + j + " is clicked.");
};
list.appendChild(item);
}
在每次循环的时候用 let j 保留的 i 的值,所以在 i 变化的时候,j 并不会变化。而console.log 的是 j,即使此处i声明换成var,结果依然一样.
MDN此处的写法是多余的,去掉let j = i依然可以实现上述效果,只是方便理解let.事实上去掉let j = i,等效于:
for (let i = 1; i <= 5; i++) {
//let i = i;即将i的作用域放在了改块级作用域中
var item = document.createElement("LI");
item.appendChild(document.createTextNode("Item " + i));
item.onclick = function (ev) {
console.log("Item " + i + " is clicked.");
};
list.appendChild(item);
}
console.log(i)// Uncaught ReferenceError: i is not defined
上边代码中最后的ReferenceError表明,i虽然在for循环{}的外层,但是实际上是被绑定在该块级作用域内的.这里和var是不一样的,var声明的i在外层,因此成为全局变量.
变量提升(hoist)
let x = "global";
(function() {
console.log(x); // Uncaught ReferenceError: x is not defined
let x = 'part';
console.log(x)
}());
众所周知,let变量没有hoist,按这个理解,函数内第一行log(x)应当是global才对,但是却报错了.去掉let x = ‘part’就没有问题,这说明后边的声明影响到了第一行的log(x).
fn();
function fn(){
var x = 1;
console.log(x,y)
var y = 2
}
执行过程:
找到所有用 function 声明的变量,在环境中「创建」这些变量。
将这些变量「初始化」并「赋值」为 function(){//具体内容}
执行代码,即fn()
函数体内找到所有用var声明的变量,在环境中「创建」这些变量
将这些变量「初始化」为 undefined。
开始执行代码,x = 1 将 x 变量「赋值」为 1
打印x = 1 ,而y还未赋值,因此为undefined
如果var改为let:找到所有用 function 声明的变量,在环境中「创建」这些变量。
将这些变量「初始化」并「赋值」为 function(){//具体内容}
执行代码,即fn()
函数体内找到所有用let声明的变量,在环境中「创建」这些变量
开始执行代码,x = 1 将 x 变量「赋值」为 1
打印 x = 1 ,而y还未「初始化」,因此Uncaught ReferenceError.这就是所谓暂时性死区.