三十一、结合数组观察闭包

三十一、结合数组观察闭包

31.1 闭包

函数本身就是闭包。

31.1.1 函数可以记住自己定义时所处的外部环境,和内部语句,这就是闭包。

1
2
3
4
5
6
7
8
9
10
11
<script>
function outer(){
var a = 10;
function inner(){
console.log(a);
}
// inner没有小括号。表示定义语句
console.log(inner);
}
outer();
</script>

UkeGIU.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
function outer(){
var a = 10;
function inner(){
console.log(a);
}
// inner没有小括号。表示定义语句
return inner;
}
// 调用outer返回的是inner函数的定义,相当于将inner()拿到外面
outer(); // 不显示
console.log(outer());

// 用 i 变量接收outer(),相当于把inner函数赋值 i
var i = outer();
i(); // 10
inner(); // 报错
</script>

UkeNRJ.png

对于inner函数,外部环境 var a = 10;内部语句console.log(a),不管我们把inner函数那到哪里,它都可以记住自己所处的外部环境(变量的作用域)和自己的内部语句。

闭包是函数天生存在的性质,不需要任何结构,只不过我们需要借助这种形式体会倒闭包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
// 形参是局部变量
function outer(x){
function inner(y){
// 当前作用域没有 x 的定义,使用outer中的 x
console.log(x + y);
}
// 返回inner定义
return inner;
}
// 将outer调用赋值给 i ,相当于将inner定义赋值的 i
// 类似于把inner拿到外部使用,能够记住自己定义时所处的外部环境 x = 10
// 类似于把inner拿到外部使用,能够记住自己定义时内部语句console.log(10 + y)
// 相当于 i = function inner(y){console.log(10 + y);}
var i = outer(10);
// 调用 i函数
i(20, 30 ,40);
// 声明一次函数 i 可以多次调用
i(100);
</script>

Uke6iD.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
// 闭包:函数能够记住定义时的外部环境和内部语句
function outer(x, y){
function inner(y){
// 作用域链根据就近原则
console.log(x + y);
}
// 调用outer(x, y),得到的是返回的inner函数
return inner;
}
// i 赋值的是inner函数
// outer(1, 2) : x = 1 y = 2
var i = outer(1, 2);
// i 是inner函数的名字,调用 i 函数, i 的实际参数是赋值给inner函数的 y
// i (10) 调用,能够记住 x = 1 ,还可以记住内部语句 console.log(1 + y)
i(10); // 11
i(20); // 21
</script>

31.1.2 闭包并不是一成不变的,函数的每一次调用都会产生一个全新的闭包。

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
<script>
function fun1(){
var a = 10;
function fun2(){
a++;
console.log(a);
}
// 调用fun1 返回的是fun2的定义
return fun2;
}

// 每一次fun1调用都产生一个全新的闭包,之间互不影响
var inn1 = fun1();
var inn2 = fun1();

inn1(); // 11
// 闭包的外部环境不是一成不变的,能够记住当前的新值,并参与计算
inn1(); // 12
inn1(); // 13

// 每一次fun1 调用都产生一个全新的闭包,inn1和inn2闭包互不影响
// 每一个闭包,外部环境是全新的内容,内部语句也是全新的
inn2(); // 11
inn2(); // 12

inn1(); // 14
</script>

31.2 结合数组观察闭包

闭包:

函数天生存在的性质,能够记住声明时所处的外部环境和内部语句

数组:

[],数组中可以保存任何数据类型,将数组中每一项存放函数,函数内部可以书写序号

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
// 声明数组,将一些函数存放在数组中
// 引用数据类型保存的地址,简单数据类型保存的值
var arr = [];
console.log(typeof arr);

for(var i = 0 ; i < 10 ; i++){
// i 表示数组索引值
// arr[i] = i;

arr[i] = function(){
return i;
}
}
/*
i=0,i<10,为真,arr[0] = function(){return i}
i=1,i<10……
i=10,i<10,为假,结束循环
*/
console.log(arr);
// 读取数组中的某一项
console.log(arr[3]);
// 查看第三项的值 函数调用()
console.log(arr[3]()); // 10
console.log(arr[1]()); // 10
// i = 10 结束循环,没有赋值,结果为undefined
console.log(arr[10]); // undefined
// i 是全局变量
console.log(i); // 10

UkeWQA.png

想要的结果为3,1。结果全部都是10

由于闭包的影响,任何一个函数i都是记住的10

函数天生存在闭包记住了i,也记住了内部语句return,当函数调用时,闭包不是一成不变的,i已经变成了10,所以所有函数的返回值都是10

解决方法:

通过IIFE解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// IIFE 函数在声明时立即调用
// 声明数组
var arr = [];
// 通过遍历书写赋值
for(var i = 0 ; i < 10 ; i++){
// i 表示索引值
(function(a){
// 用户输入a
arr[a] = function(){
return a;
}
})(i);
}
console.log(arr);
console.log(arr[1]);
console.log(arr[1]());
console.log(arr[8]());
console.log(i);

Uke5eP.png

点击查看

本文标题:三十一、结合数组观察闭包

文章作者:Mango

发布时间:2020年07月08日 - 22:05:15

最后更新:2020年07月08日 - 22:35:39

原始链接:https://mango185.github.io/post/d298a8cf.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------