闭包基础知识

什么是闭包
闭包的作用
闭包的例子

什么是闭包

1
2
3
4
5
6
(function (){
var local = '变量';
function fn(){
console.log(local);
}
})();

「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。
上面代码中的函数fn,它里面可以访问到 local 变量,那么函数fn和local变量形成一个闭包。

闭包的作用

闭包的作用是用来「间接访问一个变量」。换句话说,「隐藏一个变量」。
利用闭包可以将函数内部的变量传递到外部,从而实现在外部访问另一个函数内部的局部变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function(){
var person = window.person = {//将这个对象的Address赋给window.person
name: 'stage',
}
var a=1;//传不出去
})();
//访问上面这个立即执行函数内部的person
(function(){
var person = window.person;//获取window.person的Address,并赋给变量person
console.log(person);//可以访问到
console.log(a);//访问不到
})();

闭包的使用

如果person等于window.person,别人就可以访问到person内的数据,这样看起来很不妥。万一别人不小心修改了person内的数据怎么办。所以我们不能让别人「直接访问」这个变量。怎么办呢?
用局部变量。
但是用局部变量别人又访问不到,怎么办呢?
如何从外部读取函数内部的局部变量?暴露一个访问器(在函数的内部,再定义一个函数),让别人可以「间接访问」。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function(){
var person = {
name: 'stage',
age: 24,
}
window.addAge = function (){ //访问器
person.age++;
return person.age;
}
})();
(function(){
var person = window.person;//获取不到
console.log(person);//undefined
//无法获取person的信息,只能操作它的addAge方法
var newAge = window.addAge();
console.log(newAge);
})();

上面代码中,利用闭包,让别的函数无法获取和修改person的name和age,只能通过addAge间接给age加一,从而隐藏并保护了person内的数据。


再举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var xxx = (function(){
var a = 1;
return {
getA:function(){
return a;
},
addA:function(){
a++;
return a;
}
}
})();
xxx.addA();
xxx.getA();

总结

  • 立即执行函数使得person无法被外部访问
  • 闭包使得内部的匿名函数可以访问到person
  • window.addAge保存了匿名函数的地址,该匿名函数用来操作person
  • 从而,任何地方都可以通过window.addAge里的方法操作person,但却无法访问到person的详细数据

优化,去除window

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//赋给全局变量addAge
var addAge = (function(){
var person = {
name: 'stage',
age: 24,
}
return function (){
person.age++;
return person.age;
}
})(); //返回一个匿名函数,并赋给全局变量addAge
(function(){
var newAge = addAge();//执行返回的这个匿名函数
console.log(newAge);
})();

1
2
3
4
5
6
7
8
9
10
11
12
13
var person = (function(){
return {
sayName : function(name){
var _name = name || '无';
return _name;
},
sayAge : function(age){
var _age = age || 18;
return _age;
},
};
})();

上面代码可以写成下面这样,这样写可以清楚知道return的内容,但是需要在上面取名字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var person = (function(){
var _sayName = function(name){
var _name = name || '无';
return _name;
};
var _sayAge = function(age){
var _age = age || 18;
return _age;
};
return {
sayName : _sayName,
sayAge : _sayAge
}
})();
console.log(person.sayName('lucy')); //lucy
console.log(person.sayName());//无
console.log(person.sayAge(20));//20

再看一个例子

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
var person = (function (){
var name, age, sex;
return {
getName: function(){
return name;
},
setName: function(newName){
name = newName;
},
getAge: function(){
return age;
},
setAge: function(newAge){
age = newAge;
},
getSex: function(){
return sex;
},
setSex: function(newSex){
sex = newSex;
},
}
})();
person.setName('王花花');
console.log(person.getName());
person.setAge(20);
console.log(person.getAge());
person.setSex('女');
console.log(person.getSex());

面试题

正确打印出下标

1
2
3
4
5
<ul>
<li>index 00000</li>
<li>index 11111</li>
<li>index 22222</li>
</ul>

用闭包:

1
2
3
4
5
6
7
8
9
var oLi = document.getElementsByTagName('ul')[0].children;
for (var i = 0; i < oLi.length; i++){
(function(index){
oLi[index].onclick = function(){
console.log(index);
};
})(i);
}

闭包还有一种写法:

1
2
3
4
5
6
7
for (var i = 0; i < oLi.length; i++){
oLi[i].onclick = (function(index){
return function(){
console.log(index);
}
})(i);
}

方法三:将下标index作为对象的一个属性,添加到每个数组元素中

1
2
3
4
5
6
for (var i = 0; i < oLi.length; i++){
oLi[i].index = i;
oLi[i].onclick = function(){
console.log(this.index);
};
}
-------------本文结束感谢您的阅读-------------