var的经典问题
1
2
3
4
5
6
// setTimeout是异步的,for执行完后i=6才会执行异步任务
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);// 输出6个6
}, i * 1000);
}
闭包+立即执行函数
原理: 1.闭包:函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。 B可以访问到A中的变量,因为A中的变量此时存放在堆中。 2.立即执行函数:通过定义一个匿名函数,创建了一个新的函数作用域,相当于创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏污染全局的命名空间
1
2
3
4
5
6
7
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
})(i)
}
使用setTimeout的第三个参数
原理: setTimeout的第一个参数若是一个函数,则第三个参数会当做是该函数的参数传入
1
2
3
4
5
for (var i = 1; i <= 5; i++) {
setTimeout(function timer(i) {
console.log(i);
}, i * 1000,i);
}
用let代替var
原理: let会形成块级作用域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
// 实际流程 - 形成块级作用域
{
let i = 0
{
let ii = i
setTimeout(function timer() {
console.log(ii);
}, i * 1000);
}
i++
{
let ii = i;
setTimeout(function timer() {
console.log(ii);
}, i * 1000);
}
i++
{
let ii = i;
...
}
}
用foreach的执行函数
原理: foreach的执行函数形成了闭包
1
2
3
4
5
[1,2,3,4,5].forEach(function(data,index,arr){
setTimeout(function timer() {
console.log(data);
}, data * 1000);
})