zoukankan      html  css  js  c++  java
  • javascript高级知识点——闭包

    代码信息来自于http://ejohn.org/apps/learn/。

    先给出一个权威的定义,函数对象可以通过作用域相互关联起来,函数体内的变量可以保存在函数的作用域内,这种特性称为闭包。

    在闭包内的闭包为未释放前,作用域链上的变量一直存在。

    如果你觉得这个定义太抽象,你可以先记住javascript所有的函数都是闭包,了解函数作用域的特点也就了解了闭包,尤其是当函数内还有函数时的情况。

    闭包外面不可以引用里面

    function closure(){
        var inner = 5;
    }
    console.log(inner);//not defined

    闭包里面可以引用外面

    var outter = 3;
    function closure(){
        console.log(outter);
    }
    closure();

    怎么才可以在外面使用闭包里的变量?

    var f2;
    function f1(){
        var n=999;
        f2 = function(){
          alert(n); 
       }
    }
    f1()//执行f1初始化里面的变量。
    f2()//999

    闭包可以访问外部,闭包内的闭包可以访问其外部闭包,在最外面要访问f1闭包内的变量,调用f2即可实现。

    再抽象一点点

    function f1(){
        var n=999;
        var f2 = function(){
          alert(n); 
        }
        return f2;
    }
    var result = f1()//返回的是一个函数,是f2,但此时f1已经运行完毕。
    result()//返回的函数f2仍然可以访问f1

    在javascript中函数运行完毕,局部变量就会删除。但先前的两个本质相同的例子都是在f2运行完毕之后仍然可以引用f1的变量n,好神奇,不过这就是闭包的主要作用。

    在函数定义时会创建一个作用域链,如本题,当f2定义的时候,它就创建了这样一个作用域对象,包含所有父函数的变量——然后f2调用时,创建一个激活对象,包含自身的所有变量。所以它可以引用的变量是激活对象加作用域对象,他们合起来就是这个函数的作用域。访问顺序是,先访问自身的变量n,没有;然后查找作用域链上的n=999,找到后引用。

    问题:下面各个函数的作用域链分别为什么?

    var n = 1000;
    function f1(){
        var n=999;
        var f2 = function(){
            var n = 998;
             var f3 = function(){
                var n = 997
            }
            return f3;
        }
        return f2;
    }

    f1: n=999->n=1000;

    f2: n=998->n=999->n=1000;

    f3: n=997->n=998->n=999->n=1000;

    利用闭包模仿私有变量

    function Ninja() {   
        var slices = 0;   
        this.getSlices = function(){   
            return slices;   
        };   
        this.slice = function(){   
            slices++;   
        };  
    }
    var ninja = new Ninja();   
    ninja.slice();   
    console.log(ninja.getSlices() == 1,"我们可以函数内的函数访问内部变量silce" );  
    console.log(ninja.slices === undefined,"但这种变量我们不可以直接引用" );

    这是不是很像java中的私有变量。

    问题:下面变量的值为多少?

    var a = 5; 
    function runMe(a){ 
     console.log( a == ___, "Check the value of a." ); 
     
     function innerRun(){ 
       console.log( b == ___, "Check the value of b." ); 
       console.log( c == ___, "Check the value of c." ); 
     } 
     
     var b = 7; 
     innerRun(); 
     var c = 8; 
    } 
    runMe(6); 
     
    for ( var d = 0; d < 3; d++ ) { 
     setTimeout(function(){ 
       console.log( d == ___, "Check the value of d." ); 
     }, 100); 
    }

    最后一个有一点麻烦

    var a = 5; 
    function runMe(a){ 
     assert( a == 6, "Check the value of a." ); 
     
     function innerRun(){ 
       assert( b == 7, "Check the value of b." ); 
       assert( c == undefined, "Check the value of c." ); 
     } 
     
     var b = 7; 
     innerRun(); 
     var c = 8; 
    } 
    runMe(6); 
     
    for ( var d = 0; d < 3; d++ ) { 
     setTimeout(function(){ 
       assert( d == 3, "Check the value of d." ); 
     }, 100); 
    }

    最后一个意思是循环3次,d为1,2,3,触发了三次setTimeout,当他们100ms后,三个匿名函数执行,它们本身没有变量d,通过作用域链向上找d,此时d的值是3。

  • 相关阅读:
    linux mint 17编译android 2.3.1错误记录
    android字母索引实现ListView定位
    android实现emoji输入
    shell管道与重定向
    c3p0配置记录
    ubuntu13 eclipse菜单栏失效解决
    Proxy实现java动态代理
    ubuntu13启动屏幕亮度0解决方法
    cookie和session笔记
    linux mysql中文乱码解决
  • 原文地址:https://www.cnblogs.com/winderby/p/4065550.html
Copyright © 2011-2022 走看看