Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

Higher-Order Arrow Functions ใน JavaScript - ฟังก์ชันระดับสูง

Higher-Order Functions คือฟังก์ชันที่รับฟังก์ชันอื่นเป็นพารามิเตอร์ หรือคืนค่าฟังก์ชัน (หรือทั้งคู่) ใน JavaScript ฟังก์ชันเป็น First-Class Citizens จึงทำได้โดยธรรมชาติ Arrow Functions ทำให้เขียนสั้นกระชับขึ้น

แนวคิดพื้นฐาน

  • First-Class Functions: ฟังก์ชันเป็นค่า (Value) ได้ - assign ให้ตัวแปร, ส่งเป็น argument, return จากฟังก์ชันอื่น
  • Higher-Order Function: ฟังก์ชันที่จัดการฟังก์ชันอื่น (รับหรือคืนค่า)
  • Callback: ฟังก์ชันที่ส่งเข้าไปให้ฟังก์ชันอื่นเรียกใช้ภายหลัง

ตัวอย่าง: Double Array Elements ด้วย Higher-Order Function

<!DOCTYPE html>
<html lang="th">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Higher-Order Arrow Functions</title>
    <style>
        body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; padding: 20px; }
        .result, .sample { font-size: 18px; font-weight: 500; }
        .sample { color: rebeccapurple; }
        .result { color: red; }
        button { padding: 8px 16px; margin: 10px 0; cursor: pointer; }
    </style>
</head>
<body>
    <h1>Higher-Order Arrow Functions ใน JavaScript</h1>
    <div class="sample">[22, 33, 44, 55]</div>
    <br>
    <div class="result" id="result"></div>
    <br>
    <button class="Btn" id="processBtn">คูณ 2 ทุกตัวด้วย Higher-Order Function</button>
    <h3>กดปุ่มด้านบนเพื่อคูณ 2 ทุก Element ของ Array ข้างต้น</h3>

    <script>
        const resultEle = document.getElementById("result");
        const btn = document.getElementById("processBtn");
        
        // Arrow Function: คูณ 2
        const doubleNum = (ele) => ele * 2;
        
        const arr = [22, 33, 44, 55];
        
        // Higher-Order Function: รับ Array และ Function แล้วคืน Array ใหม่
        function doubleArray(arr, fn) {
            const doubleArr = [];
            arr.forEach((element) => {
                doubleArr.push(fn(element)); // เรียก Callback Function
            });
            return doubleArr;
        }
        
        // หรือเขียนสั้นด้วย map (Built-in Higher-Order Function)
        const doubleArrayMap = (arr, fn) => arr.map(fn);
        
        btn.addEventListener("click", () => {
            resultEle.innerHTML = `อาร์เรย์เดิม: [${arr}]
`; resultEle.innerHTML += `คูณ 2 (forEach): [${doubleArray(arr, doubleNum)}]
`; resultEle.innerHTML += `คูณ 2 (map): [${doubleArrayMap(arr, doubleNum)}]`; }); </script> </body> </html>

ผลลัพธ์

อาร์เรย์เดิม: [22, 33, 44, 55]
คูณ 2 (forEach): [44, 66, 88, 110]
คูณ 2 (map): [44, 66, 88, 110]

Built-in Higher-Order Functions ของ Array

MethodคำอธิบายCallback ParamsReturn
map(fn)แปลงแต่ละ Element → Array ใหม่(element, index, array)Array ใหม่
filter(fn)กรอง Element ที่ผ่านเงื่อนไข(element, index, array)Array ใหม่
reduce(fn, initial)รวมค่าทั้งหมดเป็นค่าเดียว(acc, element, index, array)Single Value
forEach(fn)วนลูปทำ Side Effect(element, index, array)undefined
find(fn)หา Element แรกที่ผ่านเงื่อนไข(element, index, array)Element / undefined
some(fn)มีอย่างน้อย 1 ตัวผ่านเงื่อนไข(element, index, array)Boolean
every(fn)ทุกตัวผ่านเงื่อนไข(element, index, array)Boolean
sort(fn)เรียงลำดับ (Mutates!)(a, b) → numberArray เดียวกัน
flatMap(fn)map แล้ว flat(1)(element, index, array)Array ใหม่

การสร้าง Higher-Order Functions เอง

1. Function ที่คืนค่า Function (Currying/Factory)

// สร้าง Validator
const createValidator = (rules) => (value) => {
    for (const rule of rules) {
        if (!rule.test(value)) return rule.message;
    }
    return null; // Valid
};

const emailValidator = createValidator([
    { test: v => v.includes("@"), message: "ต้องมี @" },
    { test: v => v.length > 5, message: "สั้นเกินไป" }
]);

console.log(emailValidator("a@b")); // "สั้นเกินไป"
console.log(emailValidator("test@example.com")); // null (Valid)

2. Function Composition (รวมฟังก์ชัน)

const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);

const add1 = x => x + 1;
const double = x => x * 2;
const square = x => x * x;

const compute = pipe(add1, double, square); // (x + 1) * 2 ^ 2
console.log(compute(3)); // (3+1)*2 = 8 → 8^2 = 64

3. Decorator / Wrapper (เพิ่มพฤติกรรม)

// Logger Wrapper
const withLogging = (fn) => (...args) => {
    console.log(`Calling ${fn.name} with`, args);
    const result = fn(...args);
    console.log(`Result:`, result);
    return result;
};

// Retry Wrapper
const withRetry = (fn, retries = 3) => async (...args) => {
    for (let i = 0; i < retries; i++) {
        try { return await fn(...args); }
        catch (e) { if (i === retries - 1) throw e; }
    }
};

Best Practices

  • ✅ ใช้ Built-in Methods (map, filter, reduce) แทนการเขียน Loop เอง
  • ✅ ใช้ Arrow Functions สำหรับ Callback สั้นๆ
  • ✅ หลีกเลี่ยง Side Effects ใน map/filter (Pure Functions)
  • ✅ ใช้ forEach เฉพาะ Side Effects (Logging, DOM Manipulation)
  • ⚠️ ห้าม Mutate Array ต้นฉบับใน Callback (ใช้ map สร้างใหม่)