目录
什么是闭包
当内部函数被保存到外部时,将会生成闭包,生成闭包后,内部函数依旧可以访问其所在的外部函数的变量。
两个经典逻辑案例
例一:
function test() {
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
document.write(i + " ");
}
}
return a;
}
var myArr = test();
for(var j=0;j<10;j++)
{
myArr[j]();
}
运行结果:10 10 10 10 10 10 10 10 10 10
10个10,经过for循环后 i=10,而return a 只是返回了函数内容(document.write(i + " ");)这里的 i 就一直是10。
例二:
这也是闭包的解决和防范方法:将 i(或者需要的变量等,但凡牵涉到索引的问题,一定要注意)变现。
function test(){
var arr=[];
for(i=0;i<10;i++)
{
(function(j){
arr[j]=function(){
document.write(j+" ");
}
}(i))
}
return arr;
}
var myArr=test();
for(j=0;j<10;j++)
{
myArr[j]();
}
运行结果:0 1 2 3 4 5 6 7 8 9
闭包的缺点
闭包会导致原有作用域链不释放,造成内存泄漏(被占用了,剩下的内存不是理论上应该多大的内存,并不是字面意思的泄漏)
闭包的作用
1.实现公有变量
如:函数累加器
function a(){
var num=100;
function b(){
num++;
console.log(num);
}
return b;
}
var add=a();
add();
add();
add();
2.可以做缓存(存储结构)
例1:
function test() {
var num = 100;
function a() {
num++;
console.log(num);
}
// a defined a.[[scope]] 0:testAo
// 1:GO
function b() {
num--;
console.log(num);
}
// a defined a.[[scope]] 0:testAo
// 1:GO
return [a, b];
}
var myArr = test();
myArr[0]();
// 代表a
// a doing a.[[scope]] 0:aAO
// 1:testAo(函数结束,AO依旧保留)
// 2:GO
myArr[1]();
// 代表b
// b doing b.[[scope]] 0:bAO
// 1:testAo(上一步更改过后的testAO)
// 2:GO
运行结果:101 100 两个并列的函数使用的是同一个num,即一个testAO。
例二:
function eater() {
var food = "";
var obj = {
eat: function () {
console.log("i am eating " + food);
food = "";
},
push: function (myFood) {
food = myFood;
}
}
return obj;
}
var eaters = eater();
eaters.push('banana');
eaters.eat();
结果打印:i am eating banana 。这里面的food就相当于一个存储结构。对象里面包含两个函数,返回对象相当于返回两个函数。两个函数改变的始终都是同一个变量。
多个函数闭包,公用同一个变量。这种方式相当于缓存。
3.可以实现封装,属性私有化
如:
function Wang(name,old){
var money=10000;
this.name=name;
this.old=old;
this.save=function(){
money++;
console.log(money);
}
}
var wang=new Wang('haha',46);
这里的money就相当于一个私有属性,不能直接访问。
4.模块化开发,防止污染全局变量
命名空间问题
管理变量,即使两个函数中的变量名、函数名相同也不互相影响。开发的一个功能,以后会复用,就把它保存到一个闭包里面。
var name = '123';
var init=(function(){
var name='456';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
var initWang=(function(){
var name='789';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())