关于闭包(closure)的理解

138 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情>>

关于闭包(closure)的个人理解

闭包是 js 中一个无法绕开的话题。 长久以来,我对闭包的理解是:函数返回一个内部函数,使得其内部的私有变量可以被外部使用,同时使得这个私有变量不会立即被回收掉,从而延长了其生存时间。 也就是下面这种情况:

<!-- 示例1 -->
function createAdd() {
    let x = 1;
    return function add(y){
         x += y;
         console.log(x);
    }
}

const add1 = createAdd();
add1(2); // 3
add1(2); // 5
add1(2); // 7

但实际上,是我误解了闭包的含义。 闭包并不是一个函数,或者说闭包并不仅仅是一个函数。 在 MDN 网站上我看到关于闭包的一句定义:

developer.mozilla.org/zh-CN/docs/…

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

怎么理解这句话呢? 我认为这句话的意思是,一个完整的闭包至少包含两个必要因素:

  1. 一个函数。
  2. 它捆绑的周边环境状态。

所以,我前文我才说闭包并不仅仅是一个函数。如果缺乏了它捆绑的周边环境状态,那么它也不能被称为一个闭包。 示例1,显然是符合这个要求的,那么一个闭包是不是必须要返回一个函数,让外部函数的私有变量被外部使用才能算闭包呢? 再来看下面这个例子:

<!-- 示例2 -->
function createAdd() {
    let x = 1;
     function add(y){
         x += y;
         console.log(x);
    }
    add(2)
}
createAdd();

示例2,我认为也是符合闭包要求的。虽然它并没有返回内部函数,也没有将私有变量 x 生命周期延长,但是它还是满足上述两个条件的。函数 add 是一个函数,而且它也使用了外部函数的变量,也就是绑定了周边的环境状态。

那么,相对来说,下面这个就因该不是闭包了。

<!-- 示例3 -->
function createAdd() {
    let x = 1;
     function add(y){
         console.log(y);
    }
    return add;
}
const add1 = createAdd();
add1(2); // 2

示例3,尽管是返回了一个内部函数,但是这个内部函数并没有和它的外部函数绑定周边环境。所以它不能算是一个闭包。

那是不是说只要满足上面总结的两个条件就一定是闭包呢? 比如下面这种情况:

<!-- 示例4 -->
function createAdd() {
    let x = 1;
     function add(y){
         x += y;
         console.log(x);
    }
}
createAdd();

对于示例4,内部函数 add 是一个函数(check),add 中使用了外部函数的私有变量 x,因此,它也是绑定了周边环境(check)。那么,它应该是一个闭包吗?

我认为示例4也算闭包,因为在 JavaScript 中,闭包会随着函数的创建而被同时创建。。所以,虽然内部函数 add 没有被执行,但是闭包是随着函数的创建被创建的,而不是函数执行时被创建。createAdd 函数在执行时,内部函数 add 被创建了,所以这个闭包也被创建了。 对于示例4是否属于闭包,我还是心存疑虑,希望有大佬能在评论区提示下。