JavaScript - 闭包
你好,未来的编程巨星们!? 今天,我们将踏上一段激动人心的旅程,探索JavaScript闭包的世界。别担心,如果这听起来有点吓人——我保证,在这个教程结束时,你们将成为闭包专家!所以,拿起你最喜欢的饮料,舒服地坐下来,让我们开始吧!
什么是闭包?
想象你有一个魔法的盒子,即使在关闭之后,它还能记住里面的所有东西。这就是JavaScript中闭包的本质!
闭包是一个函数,它可以访问其外部(封闭)词法作用域中的变量,即使外部函数已经返回。就像这个函数随身携带了一个小背包,里面装着它在需要时可以使用的一些变量。
让我们来看一个简单的例子:
function outerFunction(x) {
let y = 10;
function innerFunction() {
console.log(x + y);
}
return innerFunction;
}
let closure = outerFunction(5);
closure(); // 输出: 15
在这个例子中,innerFunction
是一个闭包。它“记住”了 x
和 y
的值,即使 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!
这个例子展示了如何使用闭包来创建定制化的函数。
闭包的好处
闭包提供了几个好处:
- 数据隐私
- 函数工厂
- 维护状态
让我们在表格中看一下这些好处:
好处 | 描述 | 示例 |
---|---|---|
数据隐私 | 闭包可以创建私有变量 | 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