当内部函数被保存到外部时,将会生成闭包。闭包会导致原有的作用域链不释放,造成内存泄露。
闭包的三大特点为:
1、函数嵌套函数
2、内部函数可以访问外部函数的变量
3、参数和变量不会被回收。
举个例子:
function a(){
function b(){
var bbb = 234;
document.write(aaa);
}
var aaa = 100;
return b;
}
var goal = 100;
var demo = a();
demo();
首先a定义,产生执行上下文,产生一个全局的GO对象
然后a执行,产生一个AO对象
然后在函数a中定义一个内部函数b,函数b被定义,把a的执行期上下文拿了过来,为自己所用。
然后return b;
然后函数a执行结束,销毁了自己的AO对象,可是函数b没有被执行,而是被保存了外部,于是就产生了闭包,当内部函数被保存到外部时,将会生成闭包,然后在外部定义一个demo来接收。每执行一次demo,函数b就会产生AO对象。
闭包的作用:
1.实现公有变量:函数累加器:
举个例子:
function add(){
var num = 0;
function a(){
console.log(++num);
}
return a;
}
var myAdd = add();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
myAdd();
在函数Add里面嵌套一个函数a,函数a被保存到外部,产生了闭包,在外部定义一个变量来接收。
2.可以做缓存(存储结构):eater
举个例子;
function test(){
var food = "apple";
var obj = {
eatFood : function (){
if(food != ""){
console.log("I am eating"+" "+food);
food = "";
}else{
console.log("There is nothing");
}
},
pushFood : function (myFood) {
food = myFood;
}
}
return obj;
}
var person = test();
person.eatFood();
person.eatFood();
person.pushFood('banana');
person.eatFood();
3.可以实现封装,属性私有化。
4.模块化开发,防止污染全局变量。
由于我们的编程习惯会导致闭包的产生,不必要的闭包会对编程有一定的不好的影响,那么就要解决闭包。
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(){
document.write(i);
}
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10;j++){
myArr[j]();
定义一个函数test ,在函数test的内部定义一个数组,有数组来接收函数。然后将数组返回,于是产生了闭包。然后在外部定义一个来接收内部闭包的变量。
打印出的结果是10 10 10 10 10 10 10 10 10 10
因为console.log(i)是最后才执行的,当i为10时,for循环不再执行,打印出i的值。然后在外部定义一个数组来接收。
可是这不是我们想看到的结果,如何在i=0时,打印出0,i=1时打印吃1
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
(function(j){
arr[j] = function (){
document.write(j + " ");
}
}(i));
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10;j++){
myArr[j]();
}
运用到了立即执行函数,在test里面的for循环产生了10个函数,每个函数都被保存到了外部,产生了闭包,每一个立即执行函数执行完就不会再执行,所以就产生了1对1的结果。
5、使用闭包的注意点
(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。