V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
emohacker
V2EX  ›  JavaScript

[js] 大家聊聊 “闭包--Closure” 这个前端面试必问的永恒话题

  •  1
     
  •   emohacker · 2013-05-30 15:58:55 +08:00 · 7800 次点击
    这是一个创建于 4201 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这个永恒的话题一般是这样的:

    你是如何理解闭包的?什么情况下用闭包?

    我把闭包简单理解为,是函数返回后并没有释放内存中的资源。

    个人使用情况:
    1、封装,对象有私有属性或方法不希望外部直接访问的时候。
    2、缓存。
    3、类似独立的命名空间,避免变量污染到全局的情况,比如jQuery中
    (function( window , undefined ){

    })( window );

    另一考题,以下这两种写法的效果是一样的,为什么?

    var abc = (function(){
    return{.......};
    })();

    var abc = (function(){
    return{.......};
    }());
    30 条回复    1970-01-01 08:00:00 +08:00
    typing
        1
    typing  
       2013-05-30 16:11:34 +08:00   ❤️ 4
    对于Closure, 我现在印象最深的例子是这个:
    (对比注释行的区别)

    var callbacks = [];

    for(var i = 0; i < 3; ++i){
    // callbacks.push(function() {console.log(i);});

    callbacks.push(function(i){return function(){console.log(i);};}(i));
    }

    _.each(callbacks, function(f) {f();});
    Golevka
        2
    Golevka  
       2013-05-30 17:04:28 +08:00
    没有释放内存中的资源什么的... 提到closure就不得不提到lexical scoping. 从实现角度来说确实是function definition和其所在的environment的绑定.
    xatest
        3
    xatest  
       2013-05-30 17:19:42 +08:00
    为什么回复这个话题的都是ACG头像?。。。我来打破队形,对比一下函数和闭包:
    函数 = {抽象}
    闭包 = {抽象 + upvalue + env}
    otakustay
        4
    otakustay  
       2013-05-30 17:19:51 +08:00   ❤️ 2
    我有一个专门说闭包的PPT,能把这个消化掉,我觉得闭包已经没有啥能难到你了
    https://skydrive.live.com/redir.aspx?resid=5AF9669191A78C07!197


    另外关于闭存回收的问题,我也有一个专门的博客总结过
    http://otakustay.com/about-closure-and-gc/
    yimity
        5
    yimity  
       2013-05-30 17:19:59 +08:00
    我觉得要理解闭包首先要理解词法作用域,也就是函数执行时候查找变量等的过程,从函数最里面找,一直找到最外面的函数,如果内层函数没有定义的变量在外层找到,那么就可以说这个是闭包了。也由此可见,javascript 只要是函数,都可以形成闭包。

    私有变量,函数等
    防止全局变量污染
    然后就是保存某些变量的值,防止取得值是最终结果。
    初始化等。类似于常量。

    效果是一样的,先强制表达式,然后调用。
    otakustay
        6
    otakustay  
       2013-05-30 17:22:54 +08:00
    @xatest 可见玩前端的都是些什么宅……
    emohacker
        7
    emohacker  
    OP
       2013-05-30 17:24:43 +08:00
    @typing 亲,你想通过这个例子说明一个什么问题?
    emohacker
        8
    emohacker  
    OP
       2013-05-30 17:25:33 +08:00
    @Golevka 虽然木有看懂,但是感觉很厉害的样子~
    otakustay
        9
    otakustay  
       2013-05-30 17:31:30 +08:00
    @emohacker @typing 的那个是典型装饰lift问题,很坑的一个事,运行过你会明白的,而且确实是闭包特性导致
    switch
        10
    switch  
       2013-05-30 17:35:34 +08:00
    (function( window , undefined ){

    })( window );
    這個不算是閉包,只是一個匿名函數自調用而已。
    emohacker
        11
    emohacker  
    OP
       2013-05-30 17:36:21 +08:00
    @otakustay 学习
    emohacker
        12
    emohacker  
    OP
       2013-05-30 17:47:25 +08:00
    @switch 我也挺纳闷的,之前在网上看有些人说是,看上去也有点像,就记下了,面试时是这么回答的,但是用闭包的概念去套,貌似是解释不通的。
    学艺不精,未得其精髓,深入学习中~
    Golevka
        13
    Golevka  
       2013-05-30 17:48:06 +08:00
    @otakustay 不玩前端的路过, 并表示目前的工作比较偏硬件...
    @emohacker 关于lexical scoping和closure的关系5L的解释就很易懂了. SICP ch3对此也有涉及, 并且也是用的带upward的模型.
    emohacker
        14
    emohacker  
    OP
       2013-05-30 17:48:12 +08:00
    @xatest 各种宅,哈哈哈
    xatest
        15
    xatest  
       2013-05-30 17:51:09 +08:00   ❤️ 1
    我也不玩前端的,平时用到闭包最多的是写lua,给篇专门讲闭包的文章,举了各种语言(包括js)的例子:
    https://www.ibm.com/developerworks/cn/linux/l-cn-closure/
    emohacker
        16
    emohacker  
    OP
       2013-05-30 17:52:12 +08:00
    @switch 可是通过 @yimity 5楼的回答,纠其根源。。。那个匿名函数的立即执行貌似又算是闭包。。。我还是有点不清晰
    renyuan1985
        17
    renyuan1985  
       2013-05-30 17:52:22 +08:00
    @switch 恩是的,我也这样理解的,不知道我理解的闭包对不对http://renyuanz.com/javascript-closure.html
    heroicYang
        18
    heroicYang  
       2013-05-30 21:24:35 +08:00
    直白点一句话剧透:闭包就是内部函数能访问外部的变量。如果要深究,5楼已答,但是个人觉得这个概念你越是深究反而越糊涂。
    Hongmin
        19
    Hongmin  
       2013-05-30 21:36:20 +08:00
    突然想到一点,关于C语言函数中的static变量。

    int counter() {
    static unsigned v = 0;
    return v++;
    }
    是不是一个闭包?
    davepkxxx
        20
    davepkxxx  
       2013-05-30 21:39:27 +08:00
    关于那个考题

    var abc = (func)();



    var abc = (func());

    的结果当然没区别……
    heroicYang
        21
    heroicYang  
       2013-05-30 21:48:43 +08:00
    关于考题,还有第三种写法:
    var abc = function () {
    return {};
    }();
    tangzx
        22
    tangzx  
       2013-05-30 22:57:06 +08:00   ❤️ 1
    闭包是离散数学中一个入门概念,表示一种作用域在有/无向图上的运算,其输入为图上一个点,输出为一个图上点的集合。

    编译原理中,有些计算机语言设计为:以闭包运算来决定变量的作用域

    于是,讨论这些语言时就难免讨论到闭包,于是闭包便编程一个程序员用语了
    chemzqm
        23
    chemzqm  
       2013-05-30 22:59:26 +08:00
    实践中能别用就别用闭包,看过太多闭包滥用,没法阅读的代码
    slixurd
        24
    slixurd  
       2013-05-31 01:11:45 +08:00
    @Hongmin 我觉得这样不行吧= =
    不然java的匿名内部类怎么办?
    congteng
        25
    congteng  
       2013-05-31 10:36:37 +08:00
    最简单的闭包
    var a = 1;
    function test(){
    return a + 1;
    }

    test();
    emohacker
        26
    emohacker  
    OP
       2013-05-31 11:23:06 +08:00
    理解了

    @congteng 给出了五楼的例子

    @renyuan1985
    @heroicYang
    @Hongmin
    @davepkxxx
    @heroicYang
    @tangzx
    @chemzqm
    @slixurd

    thank u guys
    AlfredZhao
        27
    AlfredZhao  
       2013-05-31 21:52:27 +08:00
    @switch 正解...闭包不是拿来装样子的,要真正理解才可以。Object:带有行为的数据,Closure:带有数据的行为...
    emohacker
        28
    emohacker  
    OP
       2013-06-10 22:30:53 +08:00
    @switch

    (function( window , undefined ){

    })( window );

    变成下面这样的时候就形成了闭包

    (function( window , undefined ){
    var abc = 'x';
    var z = function(){
    console.log(abc);
    }
    z();
    })( window );

    “一个内部函数除了可以访问自己的参数和变量,同时它也能自由访问把它嵌套在其中的父函数的参数与变量。通过函数字面量创建的函数对象包含一个连接到外部上下文的连接。这被称为闭包(closure)。它是JavaScript强大表现力的来源。”----蝴蝶书 page 27
    yakczh
        29
    yakczh  
       2013-06-10 22:35:34 +08:00
    闭包就是数据的作用域
    emohacker
        30
    emohacker  
    OP
       2013-06-10 22:41:12 +08:00
    @heroicYang 哈哈,我理解了,如果是匿名函数还有第种写法 function前加操作符 +,-,~,!
    1、
    (function(){

    })()
    2、
    (function(){

    }())
    3、
    ~function(){

    }();
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2578 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:47 · PVG 23:47 · LAX 07:47 · JFK 10:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.