☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
javascript 進階

閉包與進階函式模式

閉包(Closure)深入

// 閉包 = 函式 + 它能存取的外層變數
function createMultiplier(factor) {
    // factor 被「關」在閉包裡
    return function(number) {
        return number * factor;    // ← 可以存取外層的 factor
    };
}

let double = createMultiplier(2);  // factor = 2
let triple = createMultiplier(3);  // factor = 3

console.log(double(5));    // 10
console.log(triple(5));    // 15
// 即使 createMultiplier 已經執行完畢,factor 還活在閉包裡

閉包的實用場景

私有變數

function createBankAccount(initialBalance) {
    let balance = initialBalance;    // ← 私有變數

    return {
        deposit(amount) {
            if (amount > 0) balance += amount;
            return balance;
        },
        withdraw(amount) {
            if (amount > 0 && amount <= balance) balance -= amount;
            return balance;
        },
        getBalance() {
            return balance;
        }
    };
}

let account = createBankAccount(1000);
console.log(account.getBalance());   // 1000
account.deposit(500);
console.log(account.getBalance());   // 1500
// account.balance ← undefined(無法直接存取!)

記憶化(Memoization)

function memoize(fn) {
    let cache = {};                   // ← 快取結果

    return function(...args) {
        let key = JSON.stringify(args);
        if (cache[key] !== undefined) {
            console.log("從快取取得");
            return cache[key];
        }
        let result = fn(...args);
        cache[key] = result;
        return result;
    };
}

// 使用
let expensiveCalc = memoize((n) => {
    console.log("計算中...");
    return n * n * n;
});

expensiveCalc(5);   // "計算中..." → 125
expensiveCalc(5);   // "從快取取得" → 125(不重算!)

柯里化(Currying)

// 把多參數函式轉成一系列單參數函式
function curry(fn) {
    return function curried(...args) {
        if (args.length >= fn.length) {
            return fn(...args);
        }
        return (...moreArgs) => curried(...args, ...moreArgs);
    };
}

// 使用
function add(a, b, c) {
    return a + b + c;
}

let curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3));     // 6
console.log(curriedAdd(1, 2)(3));     // 6
console.log(curriedAdd(1)(2, 3));     // 6

// 實用:建立特化版本
let addTax = curriedAdd(1.08);        // 固定第一個參數
let addTaxAndShipping = addTax(50);   // 固定第二個參數

組合(Composition)

// 把多個函式串起來
function compose(...fns) {
    return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
}

function pipe(...fns) {
    return (value) => fns.reduce((acc, fn) => fn(acc), value);
}

// 使用
let trim = s => s.trim();
let lower = s => s.toLowerCase();
let addExclamation = s => s + "!";

// compose 從右到左:addExclamation(lower(trim("  Hello  ")))
let process1 = compose(addExclamation, lower, trim);
console.log(process1("  Hello  "));  // "hello!"

// pipe 從左到右(更直觀)
let process2 = pipe(trim, lower, addExclamation);
console.log(process2("  Hello  "));  // "hello!"

IIFE(立即執行函式)

// 定義後立刻執行,常用來建立獨立作用域
(function() {
    let secret = "私有變數";
    console.log(secret);     // ← 可以存取
})();

console.log(secret);         // ← ❌ Error(外面存取不到)

// 現代寫法:用區塊 + let/const 取代
{
    let secret = "私有變數";
    console.log(secret);
}

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊