理解 JavaScript 中的闭包

理解 JavaScript 中的闭包

闭包是 JavaScript 的难点之一。大多数教程只告诉你,闭包就是一个函数中的另外一个函数,但这只是闭包的表象。本篇文章就带你透过表象,看看闭包的本质。javascript

写 JavaScript 而不知道什么是闭包,就如同写 Java 而不知道什么是类 --- JSON之父 Douglas Crockfordjava

首先看看下面这一段代码:浏览器

// 这段代码理论上来说,是一个闭包
// 可是并不纯正
var x = 0;
function addNumber() {
    return 1 + x;
}
复制代码

上面这段代码并非纯正的闭包。x 定义在全局做用域中,因此并不能保证它不被修改。说到这里要提一下,JavaScript 是一个词法做用域的语言。这意味着在函数外定义的变量能够在函数内使用,而反过来则不行。你不能在函数外部使用一个在函数内定义的变量。微信

下面的代码是一个闭包,x 定义在函数外部。并且在函数执行完以后 addNumber 仍然能够访问到 x 的值。闭包

function closedFunction(x) {
    // 当咱们把代码用函数包裹起来时
    // 就建立了一个函数做用域
    // 传递给函数的变量都是独立的
    function addNumber() {
        return 3 + x;
    }
    return addNumber;
}
console.dir(closedFunction(3));
复制代码

在浏览器中打印出来的值证实了 x 是一个闭包模块化

那么问题来了,若是消耗函数外部的变量就是闭包,那为何下面这段代码不是闭包呢?函数

function closedFunction(x) {
    var numberItem = x + 3;
    return numberItem;
}

console.dir(closedFunction)

复制代码

当咱们调用函数时,会建立一个函数做用域并为它分配内存。这个过程会一直持续到函数执行结束,内存被释放为止。在函数执行结束后,做用域中的值也将永远消失。ui

变量的做用域不在函数外部,因此不构成闭包spa

可是若是用一个函数包裹另外一个函数,它将建立另外一个做用域 --- 它旨在告诉 JavaScript,在这个函数执行完以后不要当即销毁它。3d

下面这段代码中的变量 counter 是一个闭包,由于它在被调用的函数以外( Increment) 。

变量counter 是上述代码片断中的闭包

在某种程度上,闭包只是具备保留数据的函数。建立闭包实际上是在告诉JavaScript记住函数中事物的状态 --- 只有被使用的变量才会被视为 闭包

由于闭包是有状态函数,它们在被调用以后会记住其私有变量数据。因为变量是私有的,外部函数没法经过显示调用来访问这些私有变量。这样能够使整个函数自成一体,而且能够保护其变量免受没必要要的更改。

词法做用域

所以,JavaScript 中的闭包是一种在无需显示建立类的状况下,就能将代码模块化且自包含的方式方法。使用闭包能够实现代码的可复制性,并且不用担忧污染全局做用域。

闭包不单单是将一个函数放在另外一个函数中的行为,它是一种用于建立可防止外部更改私有变量的技术,这些变量与程序的其余部分隔离,而且具备持久性。

微信关注公众号【React从入门到精通】

相关文章
相关标签/搜索