论坛首页 Web前端技术论坛

也发个js的闭包,请多指教

浏览 6021 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-02-10   最后修改:2012-02-10

 

以下内容来自javascript高级程序设计一书,加上我的理解.

先说说变量的作用域和内存问题

每个函数在执行时都会创建自己的执行环境.当执行流进入一个函数是,函数的环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境(也就是调用它的函数的执行环境).

定义一个概念:

变量对象每个执行环境都有一个与之关联的变量对象环境中定义的所有变量和函数都保存在这个对象中.

当代码在一个环境中执行时,会创建由变量对象构成的一个作用域链作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问.


来看一个普通函数:

 

function compare(value1,value2){
	if(value1 < value2){
	    return -1;
	}else if(value1 > value2){
	    return 1;
	}else{
	    return 0;
	}
}
var result = compare(5,10);

 

将其作用域链图画出来如下:

 

 


 

第一次调用compare()函数时会创建一个包含this, arguments, value1value2的活动对象.全局执行环境的变量对象处于第二位.

全局环境的变量对象始终存在,而像compare()的变量对象,则只在函数执行过程中创建.

作用域链的本质是一个指向变量对象的指针列表,他只引用但不包含变量对象.一般来讲,当函数执行完后,局部活动对象就会被销毁.但闭包的情况又不一样.

闭包:有权访问另一个函数作用域中的变量的函数.看下面代码:

 

function createComparison(propertyName){
	return function(object1, object2){
	    var value1 = object1[propertyName];
	    var value2 = object2[propertyName];
	    if(value1 < value2){
	        return -1;
	    }else if(value1 > value2){
	        return 1;
	    }else{
	        return 0;
	    }
	};
}

 当执行下面两句代码时:

 

    var compare = createComparison('name');

    var result = compare({name: 'aaa'},{name: 'bbb'});

作用域链图如下:

 

 

 

当内部函数被执行完返回时,内部环境作用域链被销毁:

如图步骤1

createComparison函数返回时,执行步骤2,但是createComparison的活动对象不会被销毁,因为匿名函数的作用域链仍然引用这它.这个活动对象留在内存中,无法被清除.我们看到此时,createComparison函数的活动对象已经和createComparison函数没有任何联系了,而和匿名函数还是有联系的.(javascript高级程序设计一书说:只有当匿名函数被销毁后,这个createComparison函数的活动对象才会被销毁,这一点我任然不能理解,匿名函数返回后不久是被销毁了么?从图中也可以看出确实是当匿名函数销毁后才会销毁createComparison的活动对象,我的理解是:createComparison调用多次,每次调用后都会将函数代码加载到内存中,只有当彻底的清除了内存中的东西后,才会彻底销毁匿名函数,这一点希望懂的人指点).

再来说说垃圾收集机制以及为什么会产生内容泄露:

现代浏览器一般采用两个垃圾收集策略:标记清除和引用计数(具体怎么个意思,我就不说了).而大多数浏览器采用的都是标记清除.iejs采用的也是标记清除,但是对浏览器COM模型采用的确实引用计数.像下面代码:

 

var element = document.getElementById('some_element');
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

 那么他们两个互相引用,不管到什么时候引用至少为1,所以永远不会被回收.所以处理方式是手工断开他们的引用.这就是ie有名的内存泄露问题.

 

关于闭包,如果大家想深入了解的话,我的建议就是看<<javascript高级程序设计一书>>,讲解的很清晰.我欢迎大家和我讨论有关闭包和js面向对象编程的知识.

原创首发,谢谢支持!

 

 

   发表时间:2012-02-15  
不是很明。。。 看来功力不行
0 请登录后投票
   发表时间:2012-03-05  
LZ,解释的蛮好!!
0 请登录后投票
   发表时间:2012-03-06  
示意图是用什么工具画的?
0 请登录后投票
   发表时间:2012-03-06  
net_hare 写道
示意图是用什么工具画的?

word
0 请登录后投票
   发表时间:2012-03-21  
(javascript高级程序设计一书说:只有当匿名函数被销毁后,这个createComparison函数的活动对象才会被销毁,这一点我任然不能理解,匿名函数返回后不久是被销毁了么?)

我的理解是:使用“函数申明(function declarations)”或者“函数表达式(function expressions)”创建的函数对象,其[[scope]]属性包含了创建该函数的那个父函数(或者全局对象)的执行上下文。在createComparison函数内部的函数声明或者函数表达式,它们的函数对象创建是在外部函数(createComparison)的执行上下文中完成,so return 的函数对象的[[scopt]]属性会有一个__parent__属性指向createComparison函数对象的[[scope]]。
0 请登录后投票
   发表时间:2012-06-19  
哥哥  我也不是很懂
0 请登录后投票
   发表时间:2012-06-20   最后修改:2012-06-20
任何一个普通的函数都是闭包, 比如一个普通的function a(){} 它的scope就是window
0 请登录后投票
   发表时间:2012-06-22  
你这里变量就变量了,对象就对象了,变量对象,这是个什么概念。。。

只有变量指向了对象,或者变量引用了对象。。。
0 请登录后投票
   发表时间:2012-07-02  
本来有点理解的,但是被楼主的图片和文字搞得晕头转向,只有我一个人这样?
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics