JavaScript - 閉包

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