首頁  >  問答  >  主體

翻译 - 深入浅出JavaScript闭包

爱因斯坦曾说过,如果你不能给一个六岁的孩童将清楚什么是闭包,那就证明你自己也不理解。我尝试着去给一个27岁的朋友讲解,但失败了。
如果是你,你会如何去给那些不懂的人讲解闭包的概念(比如函数、变量等)?

原问题:How do JavaScript closures work?

阿神阿神2749 天前587

全部回覆(4)我來回復

  • PHPz

    PHPz2017-04-10 13:13:11

    其实这个问题恼人怪的是发明者没有搞一个图形化的界面说明后面的原理。希望有大神可以解释之,或者说难道js console有这个功能我没去试。我写这个是为了复习下看了权威指南后的心得,写下自己的理解。希望有人指正。
    函数是伴随一个定义时的scope chain.然后调用这个函数的时候会增加一个temp invoke chain 1来保存这个嵌套函数的local var + param和它外层的var + param,然后return后就被gc.但是每次调用外层函数的时候都会新生成一个temp invoke chain 2来保存内函数的作用域链,如果被返回值或者存储到其他属性而被引用就不会GC而被保存下来. 于是作用域上外函数的var就被保存下来.

    define scope chain 1: { 外函数param + localVar } -> { 内函数param + localVar } -> { globalVar } -> Temp invoke chain 1: { 临时外函数param + localVar } -> { define scope chain 2 } -> { globalVar }
    define scope chain 2: { 内函数param + localVar } -> { 外函数param + localVar } -> { globalVar } -> Temp invoke chain 2: { 重定义的内函数param + localVar } -> { 外函数param + localVar } -> { globalVar }

    // global variable here
    var randomVar = (function() {  //外函数 - define scope chain 1
        var localVar = 0;
        return function() {  //内函数 - define scope chain 2
            return localVar++;
        };
    }());  //调用时 - invoke scope chain - 伴随new define scope chain2
    
    randomVar();  // 0
    randomVar();  // 1
    randomVar();  // 2
    randomVar();  // 3
    

    ....

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-10 13:13:11

    一个函数内部还定义了另一个函数,内部函数可以调用外部函数的变量,这就是闭包。

    function foo(x) {
      var tmp = 3;
      function bar(y) {
        alert(x + y + (++tmp));
      }
      bar(10);
    }
    foo(2)
    

    上述代码输出为16,因为bar可以调用foo内的参数x,同样也可以调用foo里的tmp值。

    function foo(x) {
      var tmp = 3;
      return function (y) {
        alert(x + y + (++tmp));
      }
    }
    var bar = foo(2); // bar is now a closure.
    bar(10);
    

    上方代码的函数依旧输出16,bar还是可以调用x和tmp,即使它在函数外。但其实tmp仍然是在bar闭包之内,所以每次调用时都会进行运算。

    闭包最简单的实例:

    var a = 10;
    function test() {
      console.log(a); // will output 10
      console.log(b); // will output 6
    }
    var b = 6;
    test();
    

    当一个JavaScript函数被调用,将会创建一个新的执行环境。这个执行环境连同函数参数和父对象,还可以接收外部的声明变量。(如上例的a和b)

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-10 13:13:11

    参见我整理的文章JS闭包里的微观世界

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-10 13:13:11

    我昨天晚上终于弄明白这其中的所以然了,虽然有的艰深的闭包仍旧可能会让我楞很久,但是现在有这个自信给别人讲懂。
    可以看一下我写的这篇文章:
    http://thomasyim.strikingly.com/closure

    回覆
    0
  • 取消回覆