一、创建闭包
创建闭包的常见方式,就是在一个函数内部创建另一个函数。
二、作用域链
当某个函数被调用的时候,会创建一个执行环境和相应的作用域链,然后使用arguments初始化对象。这个对象叫做活动对象。
在作用域链中,外部函数的活动对象始终处于第二位。以此类推,直到作用域链终点——全局执行环境。 首先,让我先来看看什么叫做活动对象。
function compare(a,b){ if(a>b){ return true; }else if(a<b){ return false; }else{ return 0; } } var result=compare(5,10);//false console.log(result);
这段代码中,首先定义了compare()函数,然后在全局作用域中调用了它。在调用这个函数的时候,创建了arguments、a、b这三个活动对象。他们处在作用域链的第一位。
而result、compare被称为变量对象,他们处于全局执行环境下,在作用域链中处于第二位。
全局环境的变量对象始终存在,在函数中访问一个变量时,就会在作用域链中寻找具有相应名字的变量。函数执行完毕,活动对象就被销毁。而闭包的特殊就在于此,活动对象没有被销毁!
看这段代码:
function compare(propertyValue){ return function(obj1,obj2){ var a=obj1; var b=obj2; if(a<b){ return true; }else if(a>b){ return false; }else{ return 0; } } } var fun=compare("value"); console.log(typeof fun);//function var result=fun(5,10); console.log(result);//true
函数compare()中包含了一个匿名函数,那么,该匿名函数,也就是闭包的作用域链中,就会有compare()函数的活动对象。因此,该闭包作用域链其实有三节:
第一节,闭包的活动对象,obj1,obj2 和arguments;
第二节,compare()函数的活动对象,arguments和propertyValue;
第三节,全局变量对象,compare。
这意味着什么意思呢?就是在compare()这个函数在执行完毕以后,他的活动对象propertyValue和arguments也不会被销毁。因为匿名函数的作用域链仍然在引用这个活动对象。也就是说,compare()执行完以后,其执行环境的作用域链会被销毁,但是他的活动对象却不会被销毁。除非匿名函数被销毁。
总结:由于闭包会携带外部函数的作用域,所以它会占用更多的内存。建议不要过多使用闭包,会导致内存占用过多。
三、闭包与变量
function fun(){ var result=new Array(); for(var i=0;i<4;i++){ result[i]=function(){ return i; }; } return result; } var a=fun(); console.log(a);//Array(4) [, , , ]