JS學習筆記#21 | 閉包(Closure)

更新於 發佈於 閱讀時間約 5 分鐘

一、什麼是閉包?

閉包是指一個函數能夠「記住」它被創建時的外部環境(作用域),即使那個外部環境已經不存在了。

簡單來說,閉包就像是函數帶著一個「記憶背包」,裡面裝著它出生時能看到的變數。


二、閉包怎麼形成的?

讓我們從一個簡單的範例開始:

function outer() {
let name = "小明";
function inner() {
console.log(name); // 存取外層的 name
}
return inner; // 把內層函數返回
}

const myFunc = outer(); // outer 執行完,得到 inner 函數
myFunc(); // 輸出:小明

步驟解析

  1. outer() 執行時,定義了 name = "小明" 和 inner 函數。
  2. inner 被返回並存到 myFunc 中。
  3. outer 執行完後,按理說 name 應該消失,但 inner 卻保留了對 name 的存取權。
  4. 呼叫 myFunc() 時,仍然能輸出 "小明"。

閉包形成的條件

  1. 有一個內層函數(nested function)。
  2. 這個內層函數存取了外層函數的變數(比如 inner)。
  3. 內層函數被「帶到外面」使用(比如返回出去,或被外部變數保存)。


三、閉包的運作原理

閉包的背後是 作用域鏈(Scope Chain)

  • 當 inner 被創建時,它記住了自己能看到的變數(name)。
  • 這個記憶不是複製一份 name 的值,而是保留對 name 的「參考」(reference)。
  • 所以即使外層函數結束,內層函數還是能透過參考找到這些變數。


四、閉包的實際應用

1.計數器(狀態管理)

function createCounter() {
let count = 0; // 外層變數
return function() {
count++; // 內層函數改變它
console.log(count);
};
}

const counter = createCounter();
counter(); // 輸出:1
counter(); // 輸出:2
counter(); // 輸出:3
  • count 是 createCounter 裡的變數,外界無法直接存取,只能透過返回的函數操作。
  • 返回的函數形成閉包,記住並操作 count,就像一個帶記憶的計數器。


2.製作按鈕範例

function createButton(text) {
let message = `你點了 ${text} 按鈕`;
return function() {
console.log(message);
};
}

const btn1 = createButton("確認");
const btn2 = createButton("取消");

btn1(); // 輸出:你點了 確認 按鈕
btn2(); // 輸出:你點了 取消 按鈕

每個按鈕函數都記住了自己獨特的 message,因為閉包讓它們各自帶著自己的「記憶背包」。


3. 修復迴圈問題

// 問題:var 是函數作用域,i 被共享,迴圈結束時 i = 3。
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 輸出:3, 3, 3
}, 1000);
}

// 閉包解法:
//每個 IIFE 創建了一個獨立的作用域,num 被「封裝」在閉包中,獨立於外層的 i。
//閉包讓每個 setTimeout 回調記住自己專屬的 num 值。
for (var i = 0; i < 3; i++) {
(function(num) {
setTimeout(function() {
console.log(num); // 輸出:0, 1, 2
}, 1000);
})(i);
}


五、閉包的優點

  1. 資料隱私:像計數器一樣,外界無法直接改動 count,只能透過閉包提供的函數操作。
  2. 狀態記憶:閉包能保存變數狀態,像按鈕範例記住每個按鈕的訊息。
  3. 靈活性:可以用來解決非同步或迴圈中的變數共享問題。


六、閉包的注意事項

記憶體問題:閉包記住的變數不會被回收,如果不小心保留大物件,可能佔用記憶體。

function heavyClosure() {
let bigData = new Array(1000000).fill("資料");
return function() {
console.log(bigData[0]);
};
}
const func = heavyClosure(); // bigData 一直存在

解法:用完閉包後,讓它可以被回收(例如設為 null)。




留言
avatar-img
留言分享你的想法!
avatar-img
koko的沙龍
1會員
34內容數
koko的沙龍的其他內容
2025/04/30
React 事件處理:讓網頁動起來~ 網頁的互動性是吸引使用者、提供良好體驗的關鍵。 在 React 中,透過監聽使用者的操作(例如點擊、滑鼠移動、鍵盤輸入),並執行相應的程式碼,來實現豐富的互動效果。
Thumbnail
2025/04/30
React 事件處理:讓網頁動起來~ 網頁的互動性是吸引使用者、提供良好體驗的關鍵。 在 React 中,透過監聽使用者的操作(例如點擊、滑鼠移動、鍵盤輸入),並執行相應的程式碼,來實現豐富的互動效果。
Thumbnail
2025/04/28
在 React 的世界裡,Props 負責從父元件向子元件傳遞資料,而 State 則是負責管理元件自身的內部資料。 State 就像元件的記憶,可以儲存元件的狀態,並根據狀態的變化來更新 UI。
Thumbnail
2025/04/28
在 React 的世界裡,Props 負責從父元件向子元件傳遞資料,而 State 則是負責管理元件自身的內部資料。 State 就像元件的記憶,可以儲存元件的狀態,並根據狀態的變化來更新 UI。
Thumbnail
2025/04/27
在 React 的世界裡,元件 (Component) 就像一個個獨立的個體,各自負責 UI 的一部分,要讓這些個體協同工作,就需要一種溝通的機制,而 Props 就是組件之間通信和數據傳遞的主要方式。
Thumbnail
2025/04/27
在 React 的世界裡,元件 (Component) 就像一個個獨立的個體,各自負責 UI 的一部分,要讓這些個體協同工作,就需要一種溝通的機制,而 Props 就是組件之間通信和數據傳遞的主要方式。
Thumbnail
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
CSS 盒模型是理解和設計網頁佈局的核心概念。它包括元素的內容、填充、邊框和外邊距。
Thumbnail
CSS 盒模型是理解和設計網頁佈局的核心概念。它包括元素的內容、填充、邊框和外邊距。
Thumbnail
JSDoc 全名是 JavaScript Documentation,顧名思義是為 JavaScript 所使用的 API 文件,在程式碼內透過註解的方式撰寫,運行後 JSDoc 會自動掃描註解內容,並生成一份網頁版的文件,對於沒有使用 Typescript 開發的專案,也
Thumbnail
JSDoc 全名是 JavaScript Documentation,顧名思義是為 JavaScript 所使用的 API 文件,在程式碼內透過註解的方式撰寫,運行後 JSDoc 會自動掃描註解內容,並生成一份網頁版的文件,對於沒有使用 Typescript 開發的專案,也
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
※ 靜態資源回傳 ※ 什麼是靜態資源: 定義:是指事先準備好的資源,這些資源在伺服器上是靜態的、不會隨著每個請求而改變。 資源通常包括: 靜態 HTML 文件。 CSS。 圖像(Image)。 Video。 字體文件:google fonts。 favicon:網頁名稱旁邊的ico
Thumbnail
※ 靜態資源回傳 ※ 什麼是靜態資源: 定義:是指事先準備好的資源,這些資源在伺服器上是靜態的、不會隨著每個請求而改變。 資源通常包括: 靜態 HTML 文件。 CSS。 圖像(Image)。 Video。 字體文件:google fonts。 favicon:網頁名稱旁邊的ico
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
自訂元件生成位置顧名思義就是可以指定部分HTML區塊渲染在特定的畫面上,即使在不同組件也能把A組件內的部分畫面,展現在B組件上,以下方程式舉例。
Thumbnail
自訂元件生成位置顧名思義就是可以指定部分HTML區塊渲染在特定的畫面上,即使在不同組件也能把A組件內的部分畫面,展現在B組件上,以下方程式舉例。
Thumbnail
※ OPP第一大核心-封裝 封裝的精神在於將「方法」、「屬性」和「邏輯」包裝在類別裡面,透過類別的實例來實現。這樣外部物件不需要了解內部的實現細節,只需要知道如何使用該類別提供的接口即可。換句話說,封裝是將內部細節隱藏起來,只暴露必要的部分給使用者。 封裝的核心概念是,使用者如果想要接觸資料,只
Thumbnail
※ OPP第一大核心-封裝 封裝的精神在於將「方法」、「屬性」和「邏輯」包裝在類別裡面,透過類別的實例來實現。這樣外部物件不需要了解內部的實現細節,只需要知道如何使用該類別提供的接口即可。換句話說,封裝是將內部細節隱藏起來,只暴露必要的部分給使用者。 封裝的核心概念是,使用者如果想要接觸資料,只
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News