JavaScript - 閉包
Hello there, future coding superstars! ? 今天,我們將要踏上一段令人興奮的旅程,探索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