函数执行时的作用域链和活动对象是如何形成的及与闭包的关系
1、javascript解析器启动时就会初始化建立一个全局对象global object,这个全局对象就 拥有了一些预定义的全局变量和全局方法,如Infinity, parseInt, Math,所有程序中定义的全局变量都是这个全局对象的属性。在客户端javascript中,Window就是这个javascript的全局对象。
2、当javascript执行一个function时,会生成一个对象,称之为call object,function中的局部变量和function的参数都成为这个call object的属性,以免覆写同名的全局变量。
3、javascript解析器每次执行function时,都会为此function创建一个execution context执行环境,在此function执行环境中最重要的一点就是function的作用域链scope chain,这是一个对象链,由全局对象和活动对象构成,对象链具体构成过程见下面说明。
4、标识的查找机制:当javascript查询变量x的值时,就会检查此作用域链中第一个对象,可能是function的call object或全局对象(比如window),如果对象中有定义此x属性,则返回值,不然检查作用域链中的下一个对象是否定义x属性,在作用域链中没有找到,最后返回undefined。
5、当javascript执行一个function时,它会先将此function定义时的作用域作为其作用域链,然后创建一个活动对象(call object),置于作用域链的顶部,function的参数及内部var声明的所有局部变量都会成为此调用对象的属性。
6、this关键词指向方法的调用者,而不是以调用对象的属性存在,同一个方法中的this在不同的function调用中,可能指向不同的对象。
7、The Call Object as a Namespace。将活动对象当作命名空间使用,避免命名污染。
(function() {
// 在方法体内用var声明的所有局部变量,都是以方法调用时创建的活对象的属性形式 存在。
// 这样就避免与全局变量发生命名冲突。
})();
8、javascript中所有的function都是一个闭包,但只有当一个嵌套函数被导出到它所定义的作用域外时,这种闭包才强大。如果理解了闭包,就会理解function执行时的作用域链和活动对象,才能真正掌握javascript。
9、嵌套闭包的微观世界:在嵌套闭包时,当内部函数的引用被保存到嵌套闭包之外一个全局变量或者一个对象的属性时,在这种情况下,此内部函数有一个外部引用,并且在其外围调用函数的活动对象中有一个属性指向此内部函数。因为有其他对象引用此内部函数,所以在外围函数被调用一次后,其创建的活动对象会继续存在,并不会被垃圾回收器回收(因为引用计数不为0),内部函数的参数和局部变量都会在这个活动对象中得以维持,javascript代码任何形式都不能直接访问此活动对象,但是此活动对象是内部函数被调用时创建的作用域链的一部分,可以被内部函数访问并修改。
<html> <head> <title>循环内的闭包 应该谨慎</title> </head> <body> <ul id="list"> <li>第1条记录</li> <li>第2条记录</li> <li>第3条记录</li> <li>第4条记录</li> <li>第5条记录</li> <li>第6条记录</li> </ul> <script type="text/javascript"> var list_obj = document.getElementById("list").getElementsByTagName("li"); //获取list下面的所有li的对象数组 for (var i = 0; i <= list_obj.length; i++) { list_obj[i].onmousemove = function() { this.style.backgroundColor = "#eee"; document.title=i }; list_obj[i].onmouseout = function() { this.style.backgroundColor = "#fff"; } }</script> </body> </html> 为什么上面的代码改成下面的就好了呢?<html> <head> <title>循环内的闭包 应该谨慎</title> </head> <body> <ul id="list"> <li>第1条记录</li> <li>第2条记录</li> <li>第3条记录</li> <li>第4条记录</li> <li>第5条记录</li> <li>第6条记录</li> </ul> <script type="text/javascript"> var list_obj = document.getElementById("list").getElementsByTagName("li"); //获取list下面的所有li的对象数组 for (var i = 0; i <= list_obj.length; i++) { (function(i){ list_obj[i].onmousemove = function() { this.style.backgroundColor = "#eee"; document.title=i }; list_obj[i].onmouseout = function() { this.style.backgroundColor = "#fff"; } })(i); }</script> </body> </html>