JavaScript 闭包

JavaScript 闭包

一、变量

1、JavaScript 变量可以是局部变量或全局变量。

2、函数可以访问是有函数内部定义的变量,函数也可以访问函数外部定义的变量。

3、在web页面中全局变量属于 window 对象。

4、全局变量可应用于页面上的所有脚本。

5、局部变量只能用于定义它函数内部。对于其他的函数或脚本代码是不可用的。

6、全局和局部变量即便名称相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。

注意:变量声明是如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内定义。函数内部声明变量的时候,一定要使用var命令。

二、变量生命周期

1、全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。

2、在函数内部声明的变量,只在函数内部起作用。这些变量是局部变量,作用域是局部性的;函数的参数也是局部性的,只在函数内部起作用。

三、JavaScript 内嵌函数

1、所有函数都能访问全局变量。  

2、在 JavaScript 中,所有函数都能访问它们上一层的作用域。

3、JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量。

4、内部函数也可以像其他函数一样引用全局变量。

5、只要存在调用内部函数的可能,JavaScript就需要保留被引用的函数。而且JavaScript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,JavaScript的垃圾收集器才能释放相应的内存空间。

四、JavaScript 闭包

闭包是指有权限访问另一个函数作用域的变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

1.1实例

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();

add();
add();
add();

// 计数器为 3

1.2实例解析

变量 add 指定了函数自我调用的返回字值。

自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。

add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。

这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。

计数器受匿名函数的作用域保护,只能通过 add 方法修改。

注意: 闭包是可访问上一层函数作用域里变量的函数,即便上一层函数已经关闭。

2.1实例(一个经典错误)

页面上有若干个div, 我们想给它们绑定一个onclick方法,于是有了下面的代码:

<div id="divTest">

        <span>0</span> <span>1</span> <span>2</span> <span>3</span>

    </div>

    <div id="divTest2">

        <span>0</span> <span>1</span> <span>2</span> <span>3</span>

</div>

$(document).ready(function() {

            var spans = $("#divTest span");

            for (var i = 0; i < spans.length; i++) {

                spans[i].onclick = function() {

                    alert(i);

                }

            }

        });

很简单的功能可是却偏偏出错了,每次alert出的值都是4,简单的修改就好使了 

var spans2 = $("#divTest2 span");

        $(document).ready(function() {

            for (var i = 0; i < spans2.length; i++) {

                (function(num) {

                    spans2[i].onclick = function() {

                        alert(num);

                    }

                })(i);

            }

        });

2.2实例解析

for (var i = 0; i < spans.length; i++) {           spans[i].onclick = function() {               alert(i);           }       }

 

上面代码在页面加载后就会执行,当i的值为4的时候,判断条件不成立,for循环执行完毕,但是因为每个span的onclick方法这时候为内部函数,所以i被闭包引用,内存不能被销毁,i的值会一直保持4,直到程序改变它或者所有的onclick函数销毁(主动把函数赋为null或者页面卸载)时才会被回收。这样每次我们点击span的时候,onclick函数会查找i的值(作用域链是引用方式),一查等于4,然后就alert给我们了。而第二种方式是使用了一个立即执行的函数又创建了一层闭包,函数声明放在括号内就变成了表达式,后面再加上括号括号就是调用了,这时候把i当参数传入,函数立即执行,num保存每次i的值。

使用闭包的注意点:

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

原文地址:https://www.cnblogs.com/luodan/p/4588351.html