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

JavaScript闭包

2016-12-17 22:05 337 查看
<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);

            }

        });

只要存在调用内部函数的可能,JavaScript就需要保留被引用的函数。而且JavaScript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,JavaScript的垃圾收集器才能释放相应的内存空间(红色部分是理解闭包的关键)。

闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数,就是我们上面说的内部函数

变量的作用域

1、 内部函数也可以有自己的变量,这些变量都被限制在内部函数的作用域中

2、 每当通过引用或其它方式调用这个内部函数时,就会创建一个新的innerVar变量

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

4、 每次调用内部函数都会持续地递增这个全局变量的值

5、 变量是父函数的局部变量,内部函数也可以引用到这些变量

当内部函数在定义它的作用域的外部被引用时,就创建了该内部函数的一个闭包。这种情况下我们称既不是内部函数局部变量,也不是其参数的变量为自由变量,而称外部函数的调用环境为封闭闭包的环境。从本质上讲,如果内部函数引用了位于外部函数中的变量,相当于授权该变量能够被延迟使用。因此,当外部函数调用完成后,这些变量的内存不会被释放(最后的值会保存),闭包仍然需要使用它们

当存在多个内部函数时,很可能出现意料之外的闭包。我们定义一个递增函数,这个函数的增量为2

 

function outerFn() {

            var outerVar = 0;

            document.write("Outer function<br/>");

            function innerFn1() {

                outerVar++;

                document.write("Inner function 1\t");

                document.write("outerVar = " + outerVar + "<br/>");

            }

            function innerFn2() {

                outerVar += 2;

                document.write("Inner function 2\t");

                document.write("outerVar = " + outerVar + "<br/>");

            }

            return { "fn1": innerFn1, "fn2": innerFn2 };

        }

        var fnRef = outerFn();

        fnRef.fn1();

        fnRef.fn2();

        fnRef.fn1();

        var fnRef2 = outerFn();

        fnRef2.fn1();

        fnRef2.fn2();

        fnRef2.fn1();

 

我们映射返回两个内部函数的引用,可以通过返回的引用调用任一个内部函数,结果:

 

Outer function

Inner function 1    outerVar = 1

Inner function 2    outerVar = 3

Inner function 1    outerVar = 4

Outer function

Inner function 1    outerVar = 1

Inner function 2    outerVar = 3

Inner function 1    outerVar = 4

 

 

innerFn1和innerFn2引用了同一个局部变量,因此他们共享一个封闭环境。当innerFn1为outerVar递增一时,久违innerFn2设置了outerVar的新的起点值,反之亦然。我们也看到对outerFn的后续调用还会创建这些闭包的新实例,同时也会创建新的封闭环境,本质上是创建了一个新对象,自由变量就是这个对象的实例变量,而闭包就是这个对象的实例方法,而且这些变量也是私有的,因为不能在封装它们的作用域外部直接引用这些变量,从而确保了了面向对象数据的专有性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: