let
首先咱们从下面这段代码说起:
for (var i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
看一下结果:
10
10
10
10
10
10
10
10
10
10
setTimeout在若干毫秒后执行一个函数,并且是在for循环结束后。 for循环结束后,i的值为10。 所以当函数被调用的时候,它就只会打印出 10!这并不是我们期望得到的结果,大多数人期望输出结果是这样:
0
1
2
3
4
5
6
7
8
9
通常大多数人会想到的解决方法是利用闭包:
for (var i = 0; i < 10; i++) {
callback(i);
}
function callback(i) {
setTimeout(function () { console.log(i); }, 100 * i);
}
输出结果:
0
1
2
3
4
5
6
7
8
9
道行深点的人会想到利用立即执行的函数表达式(IIFE),当然这也是利用了闭包的原理:
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 100 * i);
})(i);
}
结果同样会输出:
0
1
2
3
4
5
6
7
8
9
这样写的好处是因为:上面用调用函数的方式创建一个命名函数会污染全局名称空间。这也意味着命名函数将一直保留,并且很容易被访问,它可能会再次被调用。我们的立即执行函数表达式不是命名的因此不会被意外调用以避免任何潜在的安全隐患。
想了解更多的“立即执行函数”,请戳:立即执行函数(IIFE)
除了上面两种方法,现在咱们还可以用一个新的变量声明let来解决问题:
for (let i = 0; i < 10 ; i++) {
setTimeout(function() {console.log(i); }, 100 * i);
}
使用let,声明的变量仅在块级作用域内有效,每次迭代也都会创建一个新作用域,所以使用let就可以很优雅的解决此类问题。当然let的作用不仅仅如此,更多信息可以访问Mozilla Developer Network
const
const记住一点就是它定义的变量是不可以再被赋值的,但是它定义的变量的内部属性是可以被修改的:
const numLivesForCat = 9;
const kitty = {
name: "Aurora",
numLives: numLivesForCat,
}
// Error
kitty = {
name: "Danielle",
numLives: numLivesForCat
};
// all "ok "
kitty.name = "Rory";
kitty.name = "Kitty";
kitty.name = "Cat";
kitty.numLives--;
对于一个变量如果你没有确实计划去修改的还是要尽量使用const,根据自己的情况来选择使用哪个变量声明。