闭包是函数和声明该函数的词法环境的组合。
词法作用域
考虑如下情况:
1 |
|
init()
创建了一个局部变量 name
和一个名为 displayName()
的函数。displayName()
是定义在 init()
里的内部函数,仅在该函数体内可用。displayName()
内没有自己的局部变量,然而它可以访问到外部函数的变量,所以 displayName()
可以使用父函数 init()
中声明的变量 name
。但是,如果有同名变量 name
在 displayName()
中被定义,则会使用 displayName()
中定义的 name
。
运行代码可以发现 displayName()
内的 alert()
语句成功的显示了在其父函数中声明的 name
变量的值。这个词法作用域的例子介绍了引擎是如何解析函数嵌套中的变量的。词法作用域中使用的域,是变量在代码中声明的位置所决定的。嵌套的函数可以访问在其外部声明的变量。
闭包
例子如下:
1 |
|
运行这段代码和之前的 init()
示例的效果完全一样。其中的不同 — 也是有意思的地方 — 在于内部函数,外部函数返回。
第一眼看上去,也许不能直观的看出这段代码能够正常运行。在一些编程语言中,函数中的局部变量仅在函数的执行期间可用。一旦 makeFunc()
执行完毕,我们会认为 name
变量将不能被访问。然而,因为代码运行得没问题,所以很显然在 JavaScript 中并不是这样的。
这个谜题的答案是,JavaScript中的函数会形成闭包。 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。在我们的例子中,myFunc
是执行 makeFunc
时创建的 返回函数实例的引用,而返回实例仍可访问其词法作用域中的变量,即可以访问到 name
。由此,当 myFunc
被调用时,name
仍可被访问,其值 Mozilla
就被传递到alert
中。
再看下面一组实例:
1 |
|
在这个示例中,我们定义了 makeAdder(x)
函数,它接受一个参数 x
,并返回一个新的函数。返回的函数接受一个参数 y
,并返回x+y
的值。
从本质上讲,makeAdder
是一个函数工厂 — 他创建了将指定的值和它的参数相加求和的函数。在上面的示例中,我们使用函数工厂创建了两个新函数 — 一个将其参数和 5 求和,另一个和 10 求和。
add5
和 add10
都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 add5
的环境中,x
为 5。而在 add10
中,x
则为 10。
注:本文转来自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures 更多详解请移步链接。