再谈闭包

来源:互联网 发布:linux 查找关键字 编辑:程序博客网 时间:2024/06/11 02:47

1.何为闭包------"一千个读者就有一千部哈姆雷特"

闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数)----官方
也就是说function都是一个闭包,而函数嵌套函数再返回函数的闭包比较强大,变量不会被GC清除。
function a(){
var n=0;
function b(){
console.log(++n)
}
return b;
}
var c = a();
c(); //1
函数a中嵌套了个函数b,返回了b,然后a外部创建了c指向a,------也就是说函数c可以调用a内部的变量n了;
所以闭包可以这么理解:链接函数内部和外部的一座桥梁。
function a(){
var n=0;
function b(){
console.log(++n)
}
return b;
}
var c = a();
c(); //1
c(); //2
c(); //3
原因就在于a是b的父函数,而b被赋给了一个全局变量c,这导致b始终在内存中,而b的存在依赖于a,因此a也始终在内存中,不会在调用结

束后,被垃圾回收机制(garbage collection)回收。 

2.为什么要用闭包

一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。 
所以闭包听起来高大上,没有驾驭之前勿乱用。
3.深入渗透

知识点:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain);
当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain

中只有window对象。
当执行函数a的时候,a会进入相应的执行环境(excution context)。
在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。
然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访

问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。
下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。
最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用

域链被设置为b所被定义的环境,即a的作用域。
到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是

说b可以访问到a中定义的所有变量和函数。函数b被c引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。
function fn(x) {  
 var g = function () { return x; } 
return g;
}
var h = fn(1);
alert(h());//1
函数h的作用域是在定义时确定的,就是说h指向的那个匿名函数在定义的时候就已经确定了作用域。那么在执行的时候,h的作用域链为:h

的活动对象->f的活动对象->window对象.
4.闭包作用

在内存中维持一个变量
通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)
5.Javascript的垃圾回收机制

在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相

引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。









原创粉丝点击