一、 闭包概念
能够读取其他函数内部变量的函数。只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
1、闭包形式
function a(){
function b(){
var bbb = 124;
console.log(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
a函数里返回一个b函数,在外部定义一个demo接收,这样就把b函数保存在了外部。
当a函数执行完毕销毁执行期上下文,但这时候b已经保存在了外部,连带着b定义时a的AO和GO保存在了外部。所以当执行demo时,仍然能访问a的AO里的aaa。
2、下面这种形式,也是把b函数保存在了外部。
var demo;
function test(){
var abc = 100;
function b(){
console.log(abc);
}
demo = b;
}
test();
demo();
3、如下函数,只有aAO定义了num, num每次自加,结果都会覆盖aAO里的num。
function a(){
var num = 100;
function b(){
num ++;
function c(){
num ++;
console.log(num);
}
c();
}
return b;
}
var demo = a();
demo(); --> 102
demo(); --> 104
二、闭包作用
1、实现公有变量
例:函数累加器
function add(){
var count = 0;
function demo(){
count ++;
console.log(count);
}
return demo;
}
var counter = add();
counter();
counter();
function add(){
var num = 0;
function a(){
console.log(++num);
}
return a;
}
var myAdd = add();
myAdd();
myAdd();
myAdd();
2、 可以做缓存(存储结构)
function test(){
var num = 100;
function a(){
num++;
console.log(num);
}
function b(){
num --;
console.log(num);
}
return[a,b];
}
var myArr = test();
myArr[0](); --> 101
myArr[1](); --> 100
function eater(){
var food = ""; --> 缓存结构
var obj = {
eat : function(){
console.log("I am eating" + food);
},
push : function(myFood){
food = myFood;
console.log(food);
}
}
return obj;
}
var eater1 = eater();
eater1.push("banana");
eater1.eat();
3、实现封装 属性私有化
function Deng(name,wife){
var prepareWife = 'xiaozhang'; --> 私有化属性,无法直接访问
this.name = name;
this.wife = wife;
this.divorce = function(){
this.wife = prepareWife;
}
this.changePrepareWife = function(target){
prepareWife = target;
}
this.sayPrepareWife = function (){
console.log(prepareWife);
}
}
var deng = new Deng('deng',"xiaoliu");
4、模块化开发 闭包防止污染全局变量
变量私有化,不会污染全局变量,可以把特定的功能写到一个闭包里,然后返回一个接口用来启动。
var name = "123";
var init = (function (){
var name = "ABC";
function callName (){
console.log(name);
}
return function (){
callName();
} //接口
}())
init();
把一个要在全局实现的功能放在局部里,防止污染全局变量
入口函数init
var initLee = (function (){
var name = "456";
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
intLee();
三、闭包缺点:
当内部函数被保存到外部时,将会产生闭包。
闭包会导致原有的作用域链不释放,造成内存泄露。
四、闭包问题
function test(){
var arr = [ ];
for(var i = 0; i < 10; i ++){
arr[i] = function(){
document.write(i+' ');
}//函数引用,未执行前,里面的i值不变
}
return arr; //返回一个含有10个函数的数组
}
var myArr = test();
for(var j = 0; j < 10; j ++){
myArr[j](); --> 执行10个函数,找此时的i = 10
}
用立即执行函数解决 打印0-9
function test(){
var arr = [ ];
for(var i = 0; i < 10; i ++){
( function(j){
// j = 0,1,2...
arr[j] = function(){
console.log(j);
}
}(i) );//返回10个立即执行函数
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j ++){
myArr[j]();
}