iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
JavaScript

入門JavaScript系列 第 19

函式應用

  • 分享至 

  • xImage
  •  

在 JavaScript 中,函式進階應用涉及處理更複雜的邏輯與特性,從高階函式到函式柯里化、函式組合、記憶化(Memoization)等,這些技巧能提升程式的可讀性、靈活性與性能。

1. 高階函式(Higher-Order Function)

高階函式是接受另一個函式作為參數或返回函式的函式。常見於陣列的處理方法,如 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]

2. 函式柯里化(Currying)

柯里化將多參數函式轉換成一系列單參數的函式,允許我們部分應用函式。

範例:柯里化函式

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

3. 函式組合(Function Composition)

函式組合是一種將多個函式組合起來的技巧,將一個函式的輸出作為下一個函式的輸入,這在處理資料流轉時特別實用。

範例:函式組合

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

4. 記憶化(Memoization)

記憶化是通過緩存函式的結果,來避免重複計算相同的輸入,從而優化性能。尤其適用於計算成本高的遞迴演算法,如斐波那契數列。

範例:簡單記憶化函式

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)); // 直接從緩存取得,無需重複計算

5. 柯里化與偏應用(Partial Application)

偏應用是部分應用函式,預設一些參數。這是函式柯里化的一種變形,用於提前固定一些參數,保留其他參數待後續填入。

範例:偏應用

function greet(greeting, name) {
  return `${greeting}, ${name}!`;
}

const sayHelloTo = greet.bind(null, 'Hello');
console.log(sayHelloTo('Alice')); // Hello, Alice!

6. 遞迴(Recursion)

遞迴是指函式自己呼叫自己,用於解決如樹結構、搜尋等問題。注意使用遞迴時,必須設置遞迴結束條件,否則會造成無限迴圈。

範例:計算階乘

function factorial(n) {
  if (n === 1) return 1; // 終止條件
  return n * factorial(n - 1);
}

console.log(factorial(5)); // 120

7. 立即執行函式(IIFE, Immediately Invoked Function Expression)

IIFE 是一種立即執行的函式,用於創建私有作用域,避免變數污染全局空間。常見於模組模式(Module Pattern)。

範例:IIFE

(function() {
  const privateVar = "This is private";
  console.log(privateVar); // "This is private"
})();
// console.log(privateVar); // 錯誤:無法訪問私有變數

8. call()apply()bind() 控制 this 的值

call()apply() 用來立即呼叫函式並指定 thisbind() 則是返回一個新的函式,綁定 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!

9. 生成器函式(Generator Functions)

生成器函式是一種可以在執行過程中暫停和恢復的函式,使用 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

10. 異步函式(Async/Await)

asyncawait 用來處理異步操作,讓非同步程式碼看起來像同步執行。它能夠簡化 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();

總結

無論是函式柯里化、函式組合、遞迴、生成器函式,還是異步操作,都能夠在開發時更靈活地處理各種情境。理解和應用這些概念,可以提高程式碼的可讀性、重用性以及性能。


上一篇
函式
下一篇
物件導向
系列文
入門JavaScript26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言