您的位置:首页 > Web前端 > JavaScript

javascript的闭包

2016-07-02 19:46 302 查看
    闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式是在一个函数的内部创建另一个函数。

闭包的形成与变量的作用域以及变量的生存周期密切相关。

执行环境与作用域

    执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为,每个执行环境都有一个与之关联的变量对象环境中定义的所有变量和函数都保存在这个对象中。

    全局环境是最外围的一个执行环境,根据ECMA实现所在的环境不同表示的执行对象也不同,在web浏览器中被认为是window对象。

某个执行环境中所有代码执行完毕后,该环境的所有变量和函数定义也随之被销毁。

    每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,函数执行完成后,栈将其弹出,又回到这之前的执行环境中。

    当代码在一个环境中执行时,会创建变量对象的一个作用域链。用途是保证对执行环境有权访问的所有变量和函数有序访问作用域链的前端,始终都是当前执行的代码所 在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象在最开始时只包含一个变量,即arguments
对象
(这个对象在全局环境中是不存在的)。作用域链中 的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延 续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象.

    作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

    javascript没有块级作用域。最明显的就是在if,for语句中的申明的变量在循环结束之后依然存在。

    使用var声明的变量会自动被添加到最接近的环境中,在函数内部,最接近的环境就是函数的局部环境;在with语句中,最接近的环境是函数环境。如果没有var声明的话就会自动被添加到全局环境中。

    在另一个函数内部定义的函数会将包含函数的活动对象添加到它的作用域链中。

闭包

作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的后一个值。因为闭包保存的是整个变量对象,而不是某个特殊的变量。

<div>1</div>
<div>2</div>
<div>3</div>
<script type="text/javascript">

var nodes =document.getElementsByTagName( 'div' );
for( var i = 0,len = nodes.length ; i < len; i++){
nodes[i].onclick = function(){
alert(i);
};
}
</script>
上面这段代码按照正常情况下,应该是点击某个div就弹出该div的索引,但是实际结果是无论点击哪个div都会弹出3.解释是onclick事件是异步触发的。当事件触发的时候,for循环已经结束,i的值已经变成3,所以onclick事件函数顺着作用域链从内到外查找变量i时,查到的值总是3.因为在onclick事件函数内部是没有定义i的,所以查找的是其外部作用域的i。所以解决方法是把每次循环的i的值都封闭起来,这样沿着作用域链查找的时候,会先找到被封闭在闭包环境中的i。
for( var i = 0,len = nodes.length ; i < len; i++){
(function( i ){
nodes[i].onclick = function(){
alert(i);
};
})(i);
}
闭包可以用来封装变量,把一些不需要暴露在全局的变量封装成私有变量。

闭包会造成的一个问题是内存泄漏,闭包里定义的变量不能被垃圾回收装置自动回收,所以如果闭包中的变量以后不需要使用的话就手动设置为null,如果之后需要使用的话,就不会存在内存泄漏意义上的说法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息