在 JavaScript 中,函式進階應用涉及處理更複雜的邏輯與特性,從高階函式到函式柯里化、函式組合、記憶化(Memoization)等,這些技巧能提升程式的可讀性、靈活性與性能。
高階函式是接受另一個函式作為參數或返回函式的函式。常見於陣列的處理方法,如 map()
、filter()
、reduce()
。
const numbers = [1, 2, 3, 4, 5];
// 篩選偶數
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4]
// 每個數字乘以2
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
柯里化將多參數函式轉換成一系列單參數的函式,允許我們部分應用函式。
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2); // 固定 a = 2
console.log(double(5)); // 10
// 簡化為箭頭函式寫法
const multiplyCurried = a => b => a * b;
console.log(multiplyCurried(3)(4)); // 12
函式組合是一種將多個函式組合起來的技巧,將一個函式的輸出作為下一個函式的輸入,這在處理資料流轉時特別實用。
const compose = (f, g) => x => f(g(x));
const addFive = x => x + 5;
const double = x => x * 2;
const addFiveThenDouble = compose(double, addFive);
console.log(addFiveThenDouble(10)); // (10 + 5) * 2 = 30
記憶化是通過緩存函式的結果,來避免重複計算相同的輸入,從而優化性能。尤其適用於計算成本高的遞迴演算法,如斐波那契數列。
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) return cache[key]; // 如果有緩存結果,則直接返回
const result = fn(...args);
cache[key] = result; // 緩存計算結果
return result;
};
}
const fibonacci = memoize(n => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(10)); // 55
console.log(fibonacci(10)); // 直接從緩存取得,無需重複計算
偏應用是部分應用函式,預設一些參數。這是函式柯里化的一種變形,用於提前固定一些參數,保留其他參數待後續填入。
function greet(greeting, name) {
return `${greeting}, ${name}!`;
}
const sayHelloTo = greet.bind(null, 'Hello');
console.log(sayHelloTo('Alice')); // Hello, Alice!
遞迴是指函式自己呼叫自己,用於解決如樹結構、搜尋等問題。注意使用遞迴時,必須設置遞迴結束條件,否則會造成無限迴圈。
function factorial(n) {
if (n === 1) return 1; // 終止條件
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
IIFE 是一種立即執行的函式,用於創建私有作用域,避免變數污染全局空間。常見於模組模式(Module Pattern)。
(function() {
const privateVar = "This is private";
console.log(privateVar); // "This is private"
})();
// console.log(privateVar); // 錯誤:無法訪問私有變數
call()
、apply()
、bind()
控制 this
的值call()
和 apply()
用來立即呼叫函式並指定 this
,bind()
則是返回一個新的函式,綁定 this
值。
call()
、apply()
和 bind()
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const person = { name: "Alice" };
greet.call(person, "Hello", "!"); // Hello, Alice!
greet.apply(person, ["Hi", "?"]); // Hi, Alice?
const boundGreet = greet.bind(person, "Hey");
boundGreet("!"); // Hey, Alice!
生成器函式是一種可以在執行過程中暫停和恢復的函式,使用 yield
關鍵字來返回一個值。這對於需要逐步生成大量資料的情況非常有用。
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
const generator = numberGenerator();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3
console.log(generator.next().done); // true
async
和 await
用來處理異步操作,讓非同步程式碼看起來像同步執行。它能夠簡化 Promise
的處理,並使異步流程更容易理解。
async function fetchData() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await response.json();
console.log(data);
} catch (error) {
console.log("Error:", error);
}
}
fetchData();
無論是函式柯里化、函式組合、遞迴、生成器函式,還是異步操作,都能夠在開發時更靈活地處理各種情境。理解和應用這些概念,可以提高程式碼的可讀性、重用性以及性能。