JavaScript - 闭包

你好,未来的编程巨星们!? 今天,我们将踏上一段激动人心的旅程,探索JavaScript闭包的世界。别担心,如果这听起来有点吓人——我保证,在这个教程结束时,你们将成为闭包专家!所以,拿起你最喜欢的饮料,舒服地坐下来,让我们开始吧!

JavaScript - Closures

什么是闭包?

想象你有一个魔法的盒子,即使在关闭之后,它还能记住里面的所有东西。这就是JavaScript中闭包的本质!

闭包是一个函数,它可以访问其外部(封闭)词法作用域中的变量,即使外部函数已经返回。就像这个函数随身携带了一个小背包,里面装着它在需要时可以使用的一些变量。

让我们来看一个简单的例子:

function outerFunction(x) {
let y = 10;
function innerFunction() {
console.log(x + y);
}
return innerFunction;
}

let closure = outerFunction(5);
closure(); // 输出: 15

在这个例子中,innerFunction 是一个闭包。它“记住”了 xy 的值,即使 outerFunction 已经执行完毕。

词法作用域

在我们更深入地了解闭包之前,我们需要理解词法作用域。这是一个听起来很高大上的术语,它简单意味着一个函数可以访问其外部作用域的变量。

let name = "Alice";

function greet() {
console.log("Hello, " + name + "!");
}

greet(); // 输出: Hello, Alice!

在这里,greet 可以访问 name 变量,因为存在词法作用域。就像 greet 可以看到其周围环境中的所有内容。

嵌套函数

闭包通常涉及嵌套函数。让我们来看一个例子:

function outer() {
let count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}

let counter = outer();
counter(); // 输出: 1
counter(); // 输出: 2

在这里,inner 嵌套在 outer 里面。魔法之所以发生,是因为 inner 记住了其外部作用域中的 count 变量,即使 outer 已经执行完毕。

返回函数

JavaScript的一个很酷的特性是函数可以返回其他函数。这是闭包的一个关键方面。

function multiplier(x) {
return function(y) {
return x * y;
};
}

let double = multiplier(2);
console.log(double(5)); // 输出: 10
console.log(double(3)); // 输出: 6

在这个例子中,multiplier 返回一个函数,该函数记住了 x 的值。这个返回的函数就是一个闭包。

计数器的困境

让我们来看一个闭包可以解决的常见问题:

function createCounter() {
let count = 0;
return {
increment: function() {
count++;
},
getCount: function() {
return count;
}
};
}

let counter = createCounter();
counter.increment();
counter.increment();
console.log(counter.getCount()); // 输出: 2

在这里,闭包允许我们拥有私有变量(count),只能通过提供的方法来访问。

示例:JavaScript闭包

让我们深入到一个更复杂的例子,以巩固我们的理解:

function makeAdder(x) {
return function(y) {
return x + y;
};
}

let add5 = makeAdder(5);
let add10 = makeAdder(10);

console.log(add5(2));  // 输出: 7
console.log(add10(2)); // 输出: 12

在这个例子中,makeAdder 创建了一个闭包,它“记住”了 x 的值。我们可以创建多个具有不同预设值加法函数。

示例

这里有一个闭包的另一个实用例子:

function createGreeter(greeting) {
return function(name) {
console.log(greeting + ", " + name + "!");
};
}

let greetHello = createGreeter("Hello");
let greetHi = createGreeter("Hi");

greetHello("Alice"); // 输出: Hello, Alice!
greetHi("Bob");      // 输出: Hi, Bob!

这个例子展示了如何使用闭包来创建定制化的函数。

闭包的好处

闭包提供了几个好处:

  1. 数据隐私
  2. 函数工厂
  3. 维护状态

让我们在表格中看一下这些好处:

好处 描述 示例
数据隐私 闭包可以创建私有变量 function counter() { let count = 0; return { increment: () => ++count, getValue: () => count }; }
函数工厂 创建具有预设参数的函数 function multiply(x) { return (y) => x * y; }
维护状态 跨函数调用跟踪数据 function createGame() { let score = 0; return { addPoint: () => ++score, getScore: () => score }; }

就这样,朋友们!我们已经穿越了闭包的土地,从基础到一些更高级的概念。记住,像任何技能一样,掌握闭包需要练习。所以,如果它立即没有点击,不要气馁——继续编码,继续尝试,很快你将像真正的JavaScript巫师一样挥舞闭包的力量!?‍♂️✨

Credits: Image by storyset