初识闭包

第一次接触闭包是在阅读JavaScript面向对象编程指南(第2版)(以下简称书1)这本书时,作者就在3.5章节提到:闭包这个概念最初接触起来是有一定难度的,所以即使您在首次阅读中没能“抓住”重点,也大可不必感到灰心丧气。后续章节中还有大量的实例可供您慢慢理解他们。但是问题来了,我在阅读了后续章节中大量的实例仍然没有理解它们,接下来怎么办作者可没说啊……不懂就搜!搜过之后我发现闭包啊就像哈姆雷特,多少个读者就有多少闭包……

第二次接触闭包是在阅读JavaScript忍者秘籍(第2版)(以下简称书2)这本书时,这本书的评价很高,也两极分化严重,但我觉得这个主要是个别情况吧。从京东预订状态时购买花了一个多月才到手,具体说是过了很久才收到,从2017一直等到了2018……

在书1中并没有给出闭包的具体定义,但在例子中作了如下说明:当我们将N的空间扩展到F以外,并止步于全局空间以内时,就产生了一件有趣的东西——闭包。首先说明书1写的非常流畅,但有些内容的深度仍然不是初次接触能够理解的。

书2:闭包允许函数访问关操作函数以外的变量。(这样是不是简单多了?)

红书:闭包是指有权访问另一个 函数作用域中的变量的函数。

MDN:闭包是函数和声明该函数的词法环境的组合。

了解了闭包的定义,我们来看一个例子(出自书1闭包):

var inner;
var F = function() {
    var b = 'local variable';
    var N = function () {
        return b;
    };
    inner = N;
};
b;    //b is not defined
F();
inner();    //local variable

函数 F 中包含了局部变量 b,因此后者在全局空间里是不可见的。我们在 F()中定义了一个新的函数 N(),并且将它赋值给了全局变量 inner。由于 N()是在 F()内部定义的,它可以访问 F()的作用域,所以即使该函数后来升级成了全局 函数,但它依然可以保留对 F()作用域的访问权。这样子我们就通过在隐藏变量b的同时拥有变量b的访问权。

我个再看一个不一样的例子(出自书1闭包,略有修改)

function F(param) {
    var N = function() {
        return param;
    }
    param++;
    return N;
}
var inner = F(123);
inner();    //124
var inner2 = F(321);
inner2();

通过var inner = F(123);来返回N;这个时候再通过inner();语句返回param,这个时候的值是累加过的,在执行F(123);返回N的时候执行的。然后我们再将F(321);赋给inner2时,返回的是322,也就是通过两次调用分别创造了两个不同的运行环境。闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

下面是来自于Javascript忍者秘籍(第2版)中使用闭包装私有变量的例子:

function Ninja() {
	var feints = 0;
	this.getFeints = function() {
		console.log(feints);
	};
	this.feint = function() {
		feints++;
	}
}
var ninja1 = new Ninja();
ninja1.feint();
ninja1.getFeints();    //1
var ninja2 = new Ninja();
ninja2.getFeints();    //0

上面的例子使用了对象和构造函数来完成闭包的例子和第二个例子几乎相同。都是通过闭包在隐藏变量的情况下通过函数来完成对变量的访问。

异步社区是一个有料、有货,又专业的IT专业图书社区,在这里可以读到最新、最热的IT类图书!

我想要社区的《JavaScript函数式编程指南》这本书,这本书是javascript函数式编程非常棒的图书,请大家帮我点赞!