搞不明白的 javascript 闭包

2016-09-03 23:39:38 +08:00
 darluc

去我的博客读一读

在 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]] 链会一直延伸至全局对象,与词法继承的长度一样。

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

继续阅读

2662 次点击
所在节点    JavaScript
7 条回复
ericls
2016-09-04 00:30:54 +08:00
不是有 let 吗
darluc
2016-09-04 10:25:24 +08:00
@ericls 文章比较老了,我这是翻译过来的
wensonsmith
2016-09-04 11:39:10 +08:00
这个写的太复杂,不通俗易懂,举得列子也不好。

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

还有这个教程里面的 https://segmentfault.com/a/1190000004365693
wshcdr
2016-09-04 14:13:25 +08:00
mark 一下
sahrechiiz
2016-09-04 20:40:44 +08:00
博客蛮好看的 是什么程序?
aitaii
2016-09-05 10:08:58 +08:00
看样子像 Hexo 。
darluc
2016-09-05 17:45:07 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/303743

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX