昨天偶然看到自己以前记录的一个闭包题目:
for (var i = 0; i < 5; i++){
setTimeout(console.log(i), i * 1000)
}
这段代码会依次输出0,1,2,3,4,但是设置的时间间隔却没有起到效果,因为console.log()是方法的调用,直接执行了。改动一下:
for (var i = 0; i < 5; i++){
setTimeout(function(){console.log(i)}, i * 1000)
}
写成函数后,输出结果是5个5,再改动一下,使用闭包:
for (var i = 0; i < 5; i++){
(function(i){setTimeout(function(){console.log(i)}, i * 1000)})(i)
}
现在可以每隔1秒依次打印0,1,2,3,4了,到这里相信大家都不陌生,可能有的已经见过很多次了。
这里面涉及的两个主要知识点是,setTimeout设置的时间是指多少秒后加入执行队列;闭包使用的i是每次传入的循环变量的值,不使用闭包时,则是直接使用的循环变量,所以在循环结束时会输出5个5。
到这里本该结束了,由于一直在实践ES2015的特性,今天重新书写这段代码时,自己是把var替换成了let,就导致不使用闭包就可以正确输出,因此查阅了MDN上let的资料。
let是具有块级作用域的,以前也知道一点,但只是模糊的知道。现在看个例子:
function test(){
var x = 1;
let y = 1;
if (true){
var x = 2; //同样的变量
let y = 2; //不同的变量
console.log('x:' + x + ' y:' + y) //2 2
}
console.log('x:' + x + ' y:' + y) //2 1
}
因此,下面这段代码中,
for (let i = 0; i < 5; i++){
setTimeout(function(){
console.log(i)
}, i * 1000)
}
匿名函数使用的是i的五个不同实例,所以可以每隔一秒依次打印0,1,2,3,4.
再来了解下let和var的其他不同:
// 在程序或者函数的顶层,let并不会像var一样在全局对象上创造一个属性
var x = 'global'; // 挂载在window对象上,成为它的一个属性
let y = 'global'; // 不挂载在window对象上
console.log(this.x); // "global"
console.log(this.y); // undefined
console.log(y); // "global"
// 在相同的函数或块作用域内用let重新声明同一个变量会引发SyntaxError
if (true) {
let foo;
let foo; // Uncaught SyntaxError: Identifier 'foo' has already been declared
}
if (true) {
var boo;
var boo; // undefined
}
//let不具有声明提升作用,var具有,但仅仅是声明提升,并不会执行赋值,所以是undefined
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError: foo is not defined
var bar = 1;
let foo = 2;
}
do_something();
和let作用域相关的其他例子:
扫描二维码关注公众号,回复:
92593 查看本文章
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // TypeError for redeclaration.
break;
}
// 以上代码会报错,可以将其中一个包含进块,如:
switch (x) {
case 0:
let foo;
break;
case 1: {
let foo; // TypeError for redeclaration.
break;
}
}
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
//
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
资料参考:MDN let