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

搞不明白的 Javascript 闭包

  •  
  •   darluc 2016 年 9 月 3 日 3215 次点击
    这是一个创建于 3521 天前的主题,其中的信息可能已经有所发展或是发生改变。

    去我的博客读一读

    在 Javascript 语言中,闭包就是一个函数,只是它上下文中的变量以引用的形式与其绑定在了一起。

    function getMeAClosure() { var canYouSeeMe = "here I am"; return (function theClosure() { return {canYouSeeIt: canYouSeeMe ? "yes" : "no"}; }); } var closure = getMeAClosure(); closure().canYouSeeIt; //"yes" 

    实际上每个 Javascript 函数在生成的时候都形成了闭包。稍后我会给大家解释闭包的产生原因和过程,然后纠正一些关于闭包的错误概念,最后再给出一些闭包的实际用例。不过首先简单介绍一下闭包相关的基础概念: Javascript 的闭包是通过 词法域 (lexical scope)变量环境 (VariableEnvironment) 实现的。

    词法域( Lexical Scope )

    “词法”这个词一般都是语言相关。所以函数的词法域是静态的,是由函数代码在源代码中的位置决定的。

    参考以下代码:

    var x = "global"; function outer() { var y = "outer"; function inner() { var x = "inner"; } } 

    函数 inner 在代码中被函数 outer 包裹着,而 outer 又被全局上下文包含在内。这样就形成了一个词法继承关系:

    global

    outer

    inner

    每个函数的外部词法域都是由词法继承关系中它的祖先决定的。因此,inner 函数的外部词法域就是由全局对象和函数 outer 组成的。

    变量环境( VariableEnvironment )

    全局对象有一个相关的执行上下文。而且每一次函数调用也会建立并进入一个新的执行上下文。这个执行上下文相对于静态的词法域是动态生成的。每一个执行上下文都确定了一个变量环境,它是在该上下文中所声明变量的容器。(ES 5 10.4 , 10.5 )

    注意,在 EcmaScript 3 中,函数的变量环境( VariableEnvironment )被称为活动对象( ActivationObject )

    以下伪代码可以用来描述变量环境

    //variableEnvironment: {x: undefined, etc.}; var x = "global" //variableEnvironment: {x: "global", etc.}; function outer() { //variableEnvironment: {y: undefined}; var y = "outer"; //variableEnvironment: {y: "outer"}; function inner() { //variableEnviroment: {x: undefined}; var x = "inner"; //variableEnvironment: {x: "inner"}; } } 

    不过,这只描述了整个图景中的一部分。每个变量环境都会继承它所属词法域的变量环境。

    [[scope]]属性

    当一个函数定义过程发生在某个执行上下文环境中时,会生成一个新的函数对象,此函数对象会包含一个名为 [[scope]] 的内部属性引用当前的变量环境。(ES 5 13.0-2 )

    每个函数都有这样一个 [[scope]] 属性,而且当函数被调用时,这个 [[scope]] 属性会被赋值给变量环境的 outerLex 属性,该属性是对外层词法环境的引用( outer lexical environment reference 简写为 outerLex )。这样一来,每个变量环境都继承了它父级的变量环境。这个 [[scope]] 链会一直延伸至全局对象,与词法继承的长度一样。

    现在让我们再来看一下伪代码:

    继续阅读

    7 条回复    2016-09-05 17:45:07 +08:00
    ericls
        1
    ericls  
       2016 年 9 月 4 日 via iPhone
    不是有 let 吗
    darluc
        2
    darluc  
    OP
       2016 年 9 月 4 日
    @ericls 文章比较老了,我这是翻译过来的
    wensonsmith
        3
    wensonsmith  
       2016 年 9 月 4 日
    这个写的太复杂,不通俗易懂,举得列子也不好。

    阮一峰写的挺好 http://es6.ruanyifeng.com/#docs/let

    还有这个教程里面的 https://segmentfault.com/a/1190000004365693
    wshcdr
        4
    wshcdr  
       2016 年 9 月 4 日
    mark 一下
    sahrechiiz
        5
    sahrechiiz  
       2016 年 9 月 4 日
    博客蛮好看的 是什么程序?
    aitaii
        6
    aitaii  
       2016 年 9 月 5 日
    看样子像 Hexo 。
    darluc
        7
    darluc  
    OP
       2016 年 9 月 5 日
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2697 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 51ms UTC 07:27 PVG 15:27 LAX 00:27 JFK 03:27
    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