JavaScript中闭包的理解

从个人认知层次出发,依次写下理解

1.接触过js的朋友大都知道下面的错误:

<style>
        span {
            background-color: #ffa500;
            cursor: pointer;
            color: #fff;
        }
    </style>
    <div id="demo">
        <span>0</span> <span>1</span> <span>2</span> <span>3</span>
    </div>
我想通过点击span得到它的序列号:
var demo = document.getElementById("demo");
    var spans = demo.children;
    for(var i=0;i<spans.length;i++){
        spans[i].onclick = function() {
            alert(i);
        }
    }
此时不管点击那个span弹出的结果都为4

那么我做如下修改:
for(var i=0;i<spans.length;i++){
        spans[i].onclick = function(num) {
            return function() {
                alert(num)
            }
        }(i);
    }

这样就能得到我们想要的结果了。这段代码 相当于:
for(var i=0;i<spans.length;i++){
        spans[i].onclick = fun(i);
        function fun(num) {
            return function() {
                alert(num)
            }
        }
    }

当然这样也是可以的:
for(var i=0;i<spans.length;i++){
        spans[i].index = i;
        spans[i].onclick = function () {
            alert(this.index);
        }
    }
2.变量作用域
下面代码
<script>
    var key = "你好吗";
    function fun() {
        var num = 10; 
        console.log(num);
        console.log(key);
    }
    fun();
    console.log(num);
</script>
控制台会输出:10      你好吗  num is not defined    这段代码中  key 为全局变量,在函数体内处处可见。执行函数fun(),他能识别key这个全局变量已及其内部变量num;控制台输出 10  你好吗  而 num属于fun()函数的内部变量,他无法在fun()函数以外被识别。控制台输出 num is  not  defined。

3.弄清了变量的作用域后,让我们试图理解下闭包的含义
在程序语言中,所谓闭包,是指语法域位于某个特定的区域,具有持续参照(读写)位于该区域内自身范围之外的执行域上的非持久型变量值能力的段落。这些外部执行域的非持久型变量神奇地保留他们在闭包最初定义(或创建)时的值。
我想很多同学可能跟我一样看了之后一脸懵逼,别急看看这个: 我们可以用一个函数,去访问另外一个函数的内部变量的方式就是闭包。也就是说:当内部函数在定义他的作用域的外部被引用时,就创建了该内部函数的一个闭包。额,还是疑惑?其实闭包就是能够读取其他函数内部变量的函数。   闭包归根结底就是一个函数。 

在弹出结果为4 的那段代码中。每个span的onclick事件为内部函数,他引用了for()内的变量i。我们称onclick函数就是闭包。该程序运行时,for循环开始执行,直到i为4时,for循环终止。由于js并不存在块级作用域,而i又是全局作用域下的变量,onclick事件并不能保存i的值。每当span被点击时,就会记录i这个变量。此时弹出i的值 4。

4.可能有些同学对修改后的第一段代码还是一头雾水,其实这里使用了一个立即执行的函数.后面的括号(i)表示把i当参数传入,函数立即执行,num(形参)用来保存得到的i的值

5.实例

如下代码一:
<script>
    function outerFun(){
        function innerFun(){
             var a=0;		
            a++;
            alert(a);
        }
        return innerFun; 
    }
    var obj=outerFun();
    obj();  obj();
    var obj2=outerFun();
    obj2();  obj2();
</script>
a为函数 innerFun()的内部变量,在被调用时每次都被重新赋值为0   该函数运行结果为 1  1  1  1 

代码二:
<script>
    var a = 0;
    function outerFun(){
        function innerFun(){
            a++;
            alert(a);
        }
        return innerFun;
    }
    var obj=outerFun();
    obj();  obj();
    var obj2=outerFun();
    obj2();  obj2();
</script>


a为全局变量,

输出结果为 :  1      2                     3               4

代码三:
<script>
    function outerFun()
    {
        var a=0;
        function innerFun()
        {
            a++;
            alert(a);
        }
        return innerFun;
    }
    var obj=outerFun();
    obj();  obj();
    var obj2=outerFun();
    obj2();  obj2();
</script>


在函数被重新定义为obj2时,变量a重新回到了他最初被定义时的值 0;


输出结果为:1         2                         1                2  (理解闭包含义)

看完三个实例的时候回头看下红字标识闭包的含义: 这些外部执行域的非持久型变量神奇地保留他们在闭包最初定义(或创建)时的值。



此文并非深层次解读,仅为本人理解。并不能保证完全正确。待以后考究。



猜你喜欢

转载自blog.csdn.net/lihchweb/article/details/53697396