V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Tonni
V2EX  ›  前端开发

Javascript 闭包的理解

  •  
  •   Tonni · 2014-06-24 23:43:47 +08:00 · 4516 次点击
    这是一个创建于 3806 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近在Stackoverflow上看了一个关于闭包的回答: http://stackoverflow.com/a/111200/3187638

    回答中有一句话:`A function doesn't have to return in order to be called a closure`,翻译下来就是说函数没有任何返回的时候就被称为闭包,例如:

    ```
    function foo(x) {
    var tmp = 3;
    function bar(y) {
    alert(x + y + (++tmp)); // will alert 16
    }
    bar(10);
    }
    foo(2);
    ```
    内部函数bar没有任何返回,只有执行逻辑代码,按照这个回答这里就创建了一个闭包。

    Javascript中闭包的特性是内部作用域可以访问外部作用域的数据,反之则不行,又及闭包是常驻内存的,不会被Javascript解释引擎的垃圾回收机制删除,如果按照上面的对创建闭包的定义,我们队下面的代码进行如下修改:

    ```
    function foo(x) {
    var tmp = 3;
    function bar(y) {
    return {
    doAdd: function (){
    console.info(x + y + (++tmp));
    },
    getTmp: function (){
    console.info(tmp);
    }
    }
    }
    var obj = bar(10);
    obj.doAdd(); // 输出16
    obj.doAdd(); // 输出17
    obj.getTmp(); // 输出5
    }
    foo(2);
    ```
    我对内部函数bar进行了修改,使其返回了一个包含两个方法的对象,执行函数,执行返回对象中的doAdd方法两次,然后执行对象中的getTmp方法,注意输出的值的变化。也就是说即使内部返回了数据这里的闭包依然存在的,并没有消失。

    我不知道是我这里理解错了,还是答主这句话真的不是很正确,还请大家给些建议。
    19 条回复    2014-06-25 16:21:34 +08:00
    jsonline
        1
    jsonline  
       2014-06-25 00:51:47 +08:00 via Android   ❤️ 1
    这个解释基本全错啊。
    1. JS 所有的函数在被执行的时候都是闭包,因为它可以访问外部作用域的数据。

    注意区分『闭包』和『对闭包的应用』。

    当你把一个函数当做返回值传递给别人时,别人就可以利用这个函数(也就是闭包)来间接访问原本他自己访问不到的变量。


    2. 闭包会被回收,你把它的引用去掉它就会被回收。
    3. 你最大的错误在于你以为有『块级作用域』。JS 里没有这个概念,只有函数作用域。

    手机码字见谅。
    jsonline
        2
    jsonline  
       2014-06-25 00:55:03 +08:00 via Android   ❤️ 1
    楼主你确定你的代码可以被成功执行么?你运行过没?
    Chenxiaoer
        3
    Chenxiaoer  
       2014-06-25 01:17:10 +08:00 via iPhone   ❤️ 1
    楼主,我是个渣渣,只是刚好在看书就顺便帮你搬运一下理论知识~ 编码时函数会大量出现,为了保证这些函数的纯粹,就需要强调“在内部保存数据和对外无副作用”两大特性,这在js中是通过函数闭包来实现的。 函数作为与函数成对的数据,在函数执行过程中处于里激活状态;闭包在函数运行结束后,保持所对应的最终数据状态。 参见:js语言精髓与编程实践 虽然是一堆废话,还是希望对你有用~~
    Chenxiaoer
        4
    Chenxiaoer  
       2014-06-25 01:18:27 +08:00 via iPhone   ❤️ 1
    打错:闭包作为与函数成对的数据
    ffffwh
        5
    ffffwh  
       2014-06-25 02:33:22 +08:00   ❤️ 2
    关键词之一:Lexical Scope
    emric
        6
    emric  
       2014-06-25 02:39:33 +08:00   ❤️ 1
    子函数能够使用其父函数作用域的变量称为闭包.
    只要闭包内的变量没有被直接或间接的引用, javascript 引擎都能够正确的回收. (IE6~8, eval 除外)
    blacktulip
        7
    blacktulip  
       2014-06-25 03:04:31 +08:00   ❤️ 4
    早晚还是英文的问题

    `回答中有一句话:`A function doesn't have to return in order to be called a closure`,翻译下来就是说函数没有任何返回的时候就被称为闭包`

    这句话的意思是:“能被称为闭包的函数未必需要返回”
    Tonni
        8
    Tonni  
    OP
       2014-06-25 08:10:02 +08:00 via Android
    @jsonline 可以,我运行过
    Tonni
        9
    Tonni  
    OP
       2014-06-25 09:32:06 +08:00
    @jsonline 其实我对闭包的理解就是一旦出现函数作用域就会形成闭包,和其它数据一样,闭包是存在于内存中的,至于能不能持久完全取决于闭包返回的数据是否还与其作用域保持链接,例如:

    ```
    function foo(x){
    var tmp = 3;
    return function (y){
    console.info(x + y + (tmp++));
    }
    }

    var fn = foo(10);
    fn(2);
    fn(2);
    ```
    这里的函数foo作用域产生的闭包就是始终存在于内存中的,因为外部有一个变量指向到了其返回的函数,返回函数创建的新的作用域又用到了foo的函数作用域中的变量tmp,所以函数foo的作用域不会被清除,闭包也就持久存在于内存中的。

    这是我对闭包的见解,不知道是否合理。
    jsonline
        10
    jsonline  
       2014-06-25 09:53:25 +08:00   ❤️ 1
    昨天用手机看看你代码看错了。1楼的第三点当我没说。
    9楼的理解是对的。
    66beta
        11
    66beta  
       2014-06-25 09:54:27 +08:00   ❤️ 1
    唉,闭包我也来回看了好几遍,每次看完都懂了,过几天完全忘记,不用就留不住啊
    jsonline
        12
    jsonline  
       2014-06-25 09:57:59 +08:00   ❤️ 1
    其实JS的闭包就是「函数可以访问其所在作用域*链*里的所有变量」。
    闭包里的一些变量不被回收是因为「变量被一个函数引用着,不能GC」,当这个函数被回收了,变量也会被回收。
    Tonni
        13
    Tonni  
    OP
       2014-06-25 09:59:56 +08:00
    @66beta 我之前看过,也是看完就忘,昨天手贱,又折腾这东西了。
    Tonni
        14
    Tonni  
    OP
       2014-06-25 10:01:10 +08:00
    @blacktulip 感谢翻译指正,看来我的英语姿势水平还需提高啊
    jsonline
        15
    jsonline  
       2014-06-25 10:03:06 +08:00
    如果你对内存占用比较干兴趣,可以看下这篇文章 http://www.cnblogs.com/rubylouvre/p/3345294.html
    ioNull
        16
    ioNull  
       2014-06-25 10:04:26 +08:00 via iPhone   ❤️ 1
    看松本行弘的书吧~里面有解释
    Tonni
        17
    Tonni  
    OP
       2014-06-25 10:13:15 +08:00
    @ioNull 嗯,已列入读书计划里面了,现在工作忙,手头还有几本书没读完。
    crazyxhz
        18
    crazyxhz  
       2014-06-25 15:49:35 +08:00   ❤️ 1
    ”`A function doesn't have to return in order to be called a closure`,翻译下来就是说函数没有任何返回的时候就被称为闭包“

    翻译就翻译错了吧,这句话的意思是:闭包不一定是要有return语句的函数(只要引用了immediate lexical scope 的变量的函数就叫做闭包)
    Tonni
        19
    Tonni  
    OP
       2014-06-25 16:21:34 +08:00
    @crazyxhz 谢谢提示。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5934 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 02:56 · PVG 10:56 · LAX 18:56 · JFK 21:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.