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

JavaScript 實戰模式

觀察者模式(Event Emitter)

class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(event, callback) {
        if (!this.events[event]) this.events[event] = [];
        this.events[event].push(callback);
        return this;
    }

    off(event, callback) {
        if (this.events[event]) {
            this.events[event] = this.events[event]
                .filter(cb => cb !== callback);
        }
        return this;
    }

    emit(event, ...args) {
        if (this.events[event]) {
            this.events[event].forEach(cb => cb(...args));
        }
        return this;
    }
}

// 使用
let bus = new EventEmitter();
bus.on("userLogin", (user) => console.log(`${user.name} 登入了`));
bus.on("userLogin", (user) => updateUI(user));
bus.emit("userLogin", { name: "小明" });

狀態機(State Machine)

class StateMachine {
    constructor(initialState, transitions) {
        this.state = initialState;
        this.transitions = transitions;
    }

    transition(action) {
        let key = `${this.state}_${action}`;
        let nextState = this.transitions[key];
        if (nextState) {
            console.log(`${this.state} → ${nextState}`);
            this.state = nextState;
            return true;
        }
        console.warn(`無效轉換:${this.state} + ${action}`);
        return false;
    }
}

// 訂單狀態機
let orderMachine = new StateMachine("pending", {
    "pending_pay": "paid",
    "paid_ship": "shipped",
    "shipped_deliver": "delivered",
    "pending_cancel": "cancelled",
    "paid_refund": "refunded"
});

orderMachine.transition("pay");      // pending → paid
orderMachine.transition("ship");     // paid → shipped
orderMachine.transition("deliver");  // shipped → delivered
orderMachine.transition("refund");   // 無效轉換

防抖與節流(完整版)

// 防抖:連續觸發只執行最後一次
function debounce(fn, delay, immediate = false) {
    let timer;
    return function(...args) {
        let callNow = immediate && !timer;
        clearTimeout(timer);
        timer = setTimeout(() => {
            timer = null;
            if (!immediate) fn.apply(this, args);
        }, delay);
        if (callNow) fn.apply(this, args);
    };
}

// 節流:固定間隔執行一次
function throttle(fn, limit) {
    let lastCall = 0;
    return function(...args) {
        let now = Date.now();
        if (now - lastCall >= limit) {
            lastCall = now;
            fn.apply(this, args);
        }
    };
}

深拷貝

// 簡單版(不支持函式、Date、RegExp 等)
function deepClone(obj) {
    return JSON.parse(JSON.stringify(obj));
}

// 現代版(推薦)
let clone = structuredClone(originalObj);

// 完整版(支持所有類型)
function deepCloneComplete(obj, seen = new WeakMap()) {
    if (obj === null || typeof obj !== "object") return obj;
    if (seen.has(obj)) return seen.get(obj);

    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);

    let clone = Array.isArray(obj) ? [] : {};
    seen.set(obj, clone);

    for (let key of Object.keys(obj)) {
        clone[key] = deepCloneComplete(obj[key], seen);
    }
    return clone;
}

請求佇列

// 控制並行請求數量
class RequestQueue {
    constructor(maxConcurrent = 3) {
        this.max = maxConcurrent;
        this.running = 0;
        this.queue = [];
    }

    async add(requestFn) {
        return new Promise((resolve, reject) => {
            this.queue.push(async () => {
                try {
                    resolve(await requestFn());
                } catch (err) {
                    reject(err);
                } finally {
                    this.running--;
                    this.processNext();
                }
            });
            this.processNext();
        });
    }

    processNext() {
        while (this.running < this.max && this.queue.length > 0) {
            this.running++;
            this.queue.shift()();
        }
    }
}

// 使用:最多同時 3 個請求
let queue = new RequestQueue(3);
let urls = ["/api/1", "/api/2", "/api/3", "/api/4", "/api/5"];

let results = await Promise.all(
    urls.map(url => queue.add(() => fetch(url).then(r => r.json())))
);

💡 大家的想法 · 0

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