Skip to content

แนวคิดหลัก

1. Pure Function (ฟังก์ชันบริสุทธิ์)

ฟังก์ชันที่ไม่มีผลกระทบต่อสถานะภายนอก (side effects) และให้ผลลัพธ์ที่คงที่สำหรับอินพุตเดียวกันเสมอ

❌ ตัวอย่างที่ผิด (Impure Function)

js
let count = 0;
function increment() {
  count += 1; // เปลี่ยนแปลงสถานะภายนอก
  return count;
}
  • ปัญหา: ฟังก์ชันนี้เปลี่ยนค่า count ซึ่งเป็นตัวแปรภายนอก ทำให้ไม่ใช่ pure function

✅ ตัวอย่างที่ถูกต้อง (Pure Function)

js
function add(a, b) {
  return a + b;
}
  • เหตุผล: ไม่มีการเปลี่ยนแปลงสถานะภายนอก และผลลัพธ์ขึ้นอยู่กับอินพุตเท่านั้น

2. Immutability (ไม่เปลี่ยนแปลงข้อมูลเดิม)

การหลีกเลี่ยงการแก้ไขข้อมูลต้นฉบับ โดยสร้างข้อมูลใหม่แทน

❌ ตัวอย่างที่ผิด (Mutable)

js
const arr = [1, 2, 3];
arr.push(4); // เปลี่ยนแปลง arr โดยตรง
  • ปัญหา: การใช้ push แก้ไขอาร์เรย์ arr เดิม ทำให้ไม่เป็น immutable

✅ ตัวอย่างที่ถูกต้อง (Immutable)

js
const arr = [1, 2, 3];
const newArr = [...arr, 4];
  • เหตุผล: ใช้ spread operator (...) เพื่อสร้างอาร์เรย์ใหม่ โดยไม่กระทบ arr เดิม

3. First-class Function (ฟังก์ชันเป็น first-class citizen)

ฟังก์ชันสามารถถูกเก็บในตัวแปร, ส่งผ่านเป็นพารามิเตอร์, หรือส่งกลับจากฟังก์ชันอื่นได้

❌ ตัวอย่างที่ผิด

  • ใน JavaScript ฟังก์ชันเป็น first-class citizen โดยธรรมชาติ จึงไม่มีตัวอย่างที่ "ไม่ใช่" first-class function ในบริบทนี้

✅ ตัวอย่างที่ถูกต้อง (First-class Function)

js
const add = (a, b) => a + b;
  • เหตุผล: ฟังก์ชันถูกเก็บในตัวแปร add ซึ่งแสดงถึงคุณสมบัติของ first-class function

4. Higher-order Function (ฟังก์ชันระดับสูง)

ฟังก์ชันที่รับฟังก์ชันอื่นเป็นพารามิเตอร์หรือส่งฟังก์ชันกลับ

❌ ตัวอย่างที่ผิด (Non-higher-order Function)

js
function add(a, b) {
  return a + b;
}
  • ปัญหา: ฟังก์ชันนี้ไม่รับฟังก์ชันเป็นพารามิเตอร์หรือส่งฟังก์ชันกลับ จึงไม่ใช่ higher-order function

✅ ตัวอย่างที่ถูกต้อง (Higher-order Function)

js
const add = (a, b) => a + b;
const higherOrder = (fn) => fn(1, 2);
higherOrder(add); // ผลลัพธ์: 3
  • เหตุผล: higherOrder รับฟังก์ชัน fn เป็นพารามิเตอร์ จึงเป็น higher-order function

5. Recursion (การเรียกฟังก์ชันตัวเอง)

ฟังก์ชันที่เรียกตัวเองเพื่อแก้ปัญหา แทนการใช้ลูป

❌ ตัวอย่างที่ผิด (Non-recursion)

js
function factorial(n) {
  let result = 1;
  for (let i = 1; i <= n; i++) {
    result *= i; // ใช้ลูปแทน recursion
  }
  return result;
}
  • ปัญหา: ใช้ลูปแทนการเรียกฟังก์ชันตัวเอง จึงไม่ใช่ recursion

✅ ตัวอย่างที่ถูกต้อง (Recursion)

js
const factorial = (n) => {
  if (n === 1) return 1;
  return n * factorial(n - 1);
};
  • เหตุผล: ฟังก์ชันเรียกตัวเองเพื่อคำนวณ factorial จึงเป็น recursion

ข้อดี

  • ความบริสุทธิ์และความคงที่: Pure functions ทำให้โค้ดคาดเดาได้และทดสอบง่าย
  • หลีกเลี่ยงผลข้างเคียง: ลดข้อผิดพลาดจากสถานะที่เปลี่ยนแปลง
  • โค้ดกระชับและอ่านง่าย: การใช้ higher-order functions และ composition ทำให้โค้ดสั้นลง
  • รองรับการประมวลผลคู่ขนาน: ไม่มีสถานะที่แชร์กัน ทำให้เหมาะกับการทำงานแบบคู่ขนาน
  • บำรุงรักษาง่าย: โค้ดที่ไม่มีผลข้างเคียงและ immutable ทำให้ดีบักและปรับปรุงง่าย

ข้อเสีย

  • เส้นโค้งการเรียนรู้: ผู้ที่คุ้นเคยกับการเขียนโค้ดแบบ imperative อาจต้องใช้เวลาปรับตัว
  • ประสิทธิภาพ: การใช้ recursion มากเกินไปอาจทำให้เกิด stack overflow หรือทำงานช้ากว่าลูป
  • การจัดการสถานะ: การหลีกเลี่ยงสถานะที่เปลี่ยนแปลงอาจทำให้การจัดการแอปพลิเคชันซับซ้อนขึ้น
  • การสนับสนุนจากภาษา: บางภาษาไม่รองรับ FP อย่างเต็มที่ ซึ่งอาจจำกัดการใช้งาน

เหมาะสำหรับ

  • การประมวลผลข้อมูล: เช่น การกรอง, การแปลงข้อมูล, หรือการลดรูป (reduce)
  • โปรแกรมแบบคู่ขนานและกระจาย: เนื่องจากไม่มีสถานะที่แชร์กัน
  • ซอฟต์แวร์ที่ต้องการความน่าเชื่อถือสูง: เช่น ระบบที่เน้นความปลอดภัยและเสถียรภาพ
  • การทดสอบหน่วย (unit testing): Pure functions ทำให้การทดสอบง่ายและแม่นยำ