JavaScript 闭包

闭包是放在函数内部且能够访问函数内部的局部变量的内部函数。

一、局部变量

具体请看:

JavaScript 基础 - 局部变量与全局变量

简单来说就是,在函数内声明的变量为局部变量,仅能在函数内被访问。

二、什么是闭包?

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function[a] together with an environment.[1] The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] Unlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.

所谓闭包,就是放在函数内部且能够访问函数内部的局部变量的内部函数。

其核心思想是:将数据以局部变量的方式放在函数之中,使其能且仅能通过闭包访问。

三、示例

假设需要做一个计数器。

1. 非闭包做法 1

1
2
3
4
5
var counter = 0;

var add = function(){
counter++;
}

数据可以被任意修改,无法保护数据。

2. 非闭包做法 2

1
2
3
4
var add = function(){
var counter = 0;
counter++;
}

这种做法虽然可以保护数据,但由于 counter 是局部函数,因此每次访问函数时,数据都会被初始化。

计数器无法正常工作。

3. 闭包做法 1

1
2
3
4
5
6
7
8
9
10
11
12
function fun() {
var counter = 0;
return function () {
return counter += 1;
}
};

var add = fun(); // 获得方法中return的闭包

add(); // 计数器目前是 1
add(); // 计数器目前是 2
add(); // 计数器目前是 3

注意:

这种方法是错误的

1
2
3
4
5
6
var add = function () {
var counter = 0;
return function () {
return counter += 1;
}
};

首先,这段代码中函数并没有被调用;

其次,add 接收的是函数的定义,而非闭包的定义。

4. 闭包做法 2

自调用函数:

1
2
3
(function() {
代码;
})(参数);
1
2
3
4
5
6
7
8
9
10
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();

add(); // 计数器目前是 1
add(); // 计数器目前是 2
add(); // 计数器目前是 3
  • 函数自调用,自动运行一次
    • 进行初始化
    • 并返回函数表达式
  • add 获得了闭包的定义
  • 通过 add 执行闭包,从而访问函数内部的局部变量

三、意义

  • 可以保护数据,使其不被随意修改

    数据能且仅能通过闭包访问,因此可以通过闭包中的逻辑代码保护数据

  • 可以保证数据一直存在于内存中,其状态能够保存

    而不会是将变量声明在局部,每次调用函数时都重新初始化

参考