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
28
function test() {
var arr = [];
for(var i = 1;i <= 10;i++){
arr[i] = function () {
console.log(i);
}
}
return arr;
}
var arr = test();
arr[7]();//11
我们期望能打印7,但实际打印的是11
我们把for循环拆开
function test(){
var arr = [];
i = 1;
arr[1] = function(){console.log(i)}
i = 2;
arr[2] = function(){console.log(i)}
.......
arr[10] = function(){console.log(i)}
i = 11;
根据闭包的知识,我们可以知道,这十个函数,访问的都是 i = 11;
}
解决办法 版本1.0 用闭包解决闭包
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function test() {
var arr = [];
for(var i = 1;i <= 10;i++){
(function (j) {
arr[j] = function () {
console.log(j);
}
})(i);
}
return arr;
}
var arr = test();
arr[7]();//输出7
解决了, 这是为什么呢?
我们拆一下for
function test() {
var arr = [];
i = 1;
(function (j) {//这是立即执行的
arr[j] = function () {
console.log(j);//本函数内没有,就找最近AO里的j//而j不是 test AO里的变量
//每个函数的j都在各自的AO里,所以互不影响.
//因为立即执行,j又会被i赋值;不会受到i的变化.
//第一次接触学习的时候,我也很懵逼,习惯了就好理解了.
}
})(i);
}
i = 2;
(function (j) {
arr[j] = function () {
console.log(j);
}
})(i);
}
....
i=10
(function (j) {
arr[j] = function () {
console.log(j);
}
})(i);
}
i = 11
return arr;
}
var arr = test();
arr[7]();
版本2.0 forEach
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
bug版1.0
function test() {
var arr = Array(10);//第一个没想到的是,空数组forEach不循环;
arr.forEach(function (item, index) {
item = function () {
console.log(index);
}
})
return arr;
}
var arr = test();
arr[7]();
bug版1.1
function test() {
var arr = [1,1,1,1,1,1,1,1,1,1];//这个样子挺蠢的,哈哈
arr.forEach(function (item, index) {
item = function () {//问题出在item,我赋值给item并不能影响arr,即使我改成arr = [[],...,[]];
console.log(index);
}
})
return arr;
}
var arr = test();
arr[7]();
修补bug版1.2
function test() {
var arr = [1,1,1,1,1,1,1,1,1,1];
arr.forEach(function (item, index) {
console.log(item);
arr[index] = function () {
console.log(index);
}
})
return arr;
}
var arr = test();
arr[7]();
由于实在不理解为什么arr = Array(10); forEach根本就不执行,一次循环都不执行
所以我用模拟的forEach 试了一下
Array.prototype.myForEach = function (fn,context) {
var context = context || window;
var arr = this;
var len = arr.length;
for(var i = 0;i < len;i++){
fn.call(context,arr[i],i,arr);
}
}
function test() {
var arr = Array(10);
arr.myForEach(function (item, index) {
console.log(item);
arr[index] = function () {
console.log(index);
}
})
return arr;
}
var arr = test();
arr[7]();//输出 7
这个测试有个很明显的结论,模拟写的myForEach 肯定和原生 forEach 有区别.
在这个案例上,用forEach感觉很蠢,我也没想到,
主要是因为,这个案例上,我们主要是赋值操作.
如果取值操作的话,很多时候能很自然的解决闭包问题.
为什么forEach 能解决问题? 看这一段
for(var i = 0;i < len;i++){
fn.call(context,arr[i],i,arr);
}
这里for循环里面fn() 是执行形态(应该叫表达式),所以不受影响,
自己可以再想想.
版本3.0 ES6 let 取代var
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
关于let 和ES6的更多知识可以自行百度
function test () {
var arr = [];
for(let i = 1; i <= 10;i++ ){
arr[i] = function () {console.log(i)}
}
return arr;
}
var arr = test();
arr[7]();
let 是块级作用域,
这里的关键是 for(let i) 括号里是一个单独的块级作用域.
其实就算这样也不太好理解.
我们拆开for
function test () {
var arr = []
{let i=1
{
arr[i] = function () {console.log(i)}
}
}
{let i=2
{
arr[i] = function () {console.log(i)}
}
}
}
....
{let i=10
{
arr[i] = function () {console.log(i)}
}
}
只能这么理解,但我也觉得有地方说不通. 如果每次生成一个块级重新声明 let i,
那么每个i都是独立的,应该没有关系,但很明显应该是同一个i ,起码后一个i受到前一个i的影响.
如果是同一个i,那么就算独立拥有一个块级,也应该无法满足需求.
比如这样拆for
{
let i=0;
{
arr[i] = function () {console.log(i)}
}
i = 1;
{
arr[i] = function () {console.log(i)}
}
...
i = 10;
{
arr[i] = function () {console.log(i)}
}
i = 11
}
如果是这样的话,应该达不到想要的效果.
当然了,我们只需要知道 for + let的时候可以解决这个问题就行了.