跳到主要内容

JavaScript 闭包

提示
  1. 嵌套函数和函数返回:在JavaScript中,一个函数可以包含另一个函数(嵌套函数),并且一个函数可以返回另一个函数。
  2. 闭包定义:闭包允许从内部函数访问外部函数的作用域,即使外部函数已经执行完毕。
  3. 数据隐私:闭包有助于程序中的数据隐私,使得某些变量只能在特定函数内部访问和修改。

在了解闭包之前,您需要理解两个概念:

  • 嵌套函数
  • 返回函数

JavaScript嵌套函数

在JavaScript中,一个函数可以包含另一个函数。这被称为嵌套函数。例如,

// 嵌套函数示例

// 外部函数
function greet(name) {
// 内部函数
function displayName() {
console.log("Hi" + " " + name);
}

// 调用内部函数
displayName();
}

// 调用外部函数
greet("John"); // Hi John

在上面的程序中,greet() 函数内部包含了 displayName() 函数。

返回函数

在JavaScript中,您也可以在函数内部返回一个函数。例如,

function greet(name) {
function displayName() {
console.log("Hi" + " " + name);
}

// 返回一个函数
return displayName;
}

const g1 = greet("John");
console.log(g1); // 返回函数定义
g1(); // 调用函数

输出

function displayName() {
console.log('Hi' + ' ' + name);
}
Hi John

在上面的程序中,greet() 函数返回了 displayName 函数的定义。

这里,返回的函数定义被分配给了 g1 变量。当您使用 console.log(g1) 打印 g1 时,您将得到函数定义。

要调用存储在 g1 变量中的函数,我们使用带括号的 g1()

JavaScript 闭包

在JavaScript中,闭包允许从内部函数访问外部函数的作用域,即使外部函数已经关闭。例如,

// javascript 闭包示例

// 外部函数
function greet() {
// 在内部函数之外定义的变量
let name = "John";

// 内部函数
function displayName() {
// 访问name变量
return "Hi" + " " + name;
}

return displayName;
}

const g1 = greet();
console.log(g1); // 返回函数定义
console.log(g1()); // 返回值

输出

function displayName() {
// 访问name变量
return 'Hi' + ' ' + name;
}
Hi John

在上面的示例中,当调用 greet() 函数时,它返回 displayName 函数的定义。

这里,g1 是对 displayName() 函数的引用。

当调用 g1() 时,它仍然可以访问 greet() 函数。

当我们运行 console.log(g1) 时,它返回函数定义。

闭包的概念也存在于其他编程语言中,如Python、Swift、Ruby等。

让我们看另一个示例。

// 闭包示例

function calculate(x) {
function multiply(y) {
return x * y;
}
return multiply;
}

const multiply3 = calculate(3);
const multiply4 = calculate(4);

console.log(multiply3); // 返回calculate函数定义
console.log(multiply3()); // NaN

console.log(multiply3(6)); // 18
console.log(multiply4(2)); // 8

在上述程序中,calculate() 函数接受一个参数 x 并返回 multiply() 函数的定义。multiply() 函数接受一个参数 y 并返回 x * y

multiply3multiply4 都是闭包。

调用 calculate() 函数传递一个参数 x。当调用 multiply3(6)multiply4(2) 时,multiply() 函数可以访问外部 calculate() 函数传递的 x 参数。

数据隐私

JavaScript 闭包有助于程序的数据隐私。例如,

let a = 0;
function sum() {
function increaseSum() {
// a 的值增加了 1
return (a = a + 1);
}
return increaseSum;
}

const x = sum();
console.log(x()); // 1
console.log(x()); // 2
console.log(x()); // 3
a = a + 1;
console.log(a); // 4

在上面的例子中,sum()函数返回了increaseSum()函数的函数定义。

变量 a 在increaseSum()函数内部被增加。然而,a 变量的值也可以在函数外部被改变。在这种情况下,a = a + 1;在函数外部改变了变量的值。

现在,如果您想让 a 变量只在函数内部增加,您可以使用闭包。例如,

function sum() {
let a = 0;
function increaseSum() {
// a 的值增加了 1
return (a = a + 1);
}
return increaseSum;
}

let x = sum();
let a = 5;
console.log(x()); // 1
console.log(x()); // 2
console.log(a); // 5

在上面的例子中,sum()函数将 a 的值设置为 0 并返回increaseSum()函数。

由于闭包的原因,即使sum()已经执行,increaseSum()仍然可以访问 a 并且每次调用x()时都可以给 a 加上 1

并且 a 变量对sum()函数是私有的。这意味着 a 变量只能在sum()函数内部被访问。

即使您声明a并使用它,也不会影响sum()函数内部的 a 变量。

注意:通常,闭包用于数据隐私。