[js] 大家聊聊 “闭包--Closure” 这个前端面试必问的永恒话题 - V2EX
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 8374 次点击
    这是一个创建于 4576 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这个永恒的话题一般是这样的:

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

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

    个人使用情况:
    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/span>
    @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 +8: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
    @dvepkxxx
    @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     Solana     4518 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 05:37 PVG 13:37 LAX 21:37 JFK 00:37
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86