JavaScript
Functions
Function expression
เข้าใจการเก็บฟังก์ชันไว้ในตัวแปรด้วย Function Expression รูปแบบ const fn = function() {} การประกาศก่อนเรียกใช้ และการใช้ร่วมกับ return, default value และเงื่อนไขพื้นฐาน
Function Expression คือการเก็บฟังก์ชันไว้ในตัวแปร
Function Expression คือการสร้างฟังก์ชันแล้วนำฟังก์ชันนั้นไปเก็บไว้ในตัวแปร รูปแบบที่เจอบ่อยที่สุดคือ `const fn = function (...) { ... }` เมื่ออยากใช้งาน เราจะเรียกผ่านชื่อตัวแปรนั้น
สร้างฟังก์ชันเก็บไว้ในตัวแปร `sayHello` แล้วเรียกใช้ผ่านชื่อตัวแปร
const sayHello = function(name) {
return "สวัสดี " + name;
};
console.log(sayHello("มิน")); // สวัสดี มินให้มองว่า `sayHello` เป็นตัวแปรที่ตอนนี้เก็บ "ฟังก์ชัน" อยู่ด้านใน เพราะฉะนั้นเราจึงเรียก `sayHello(...)` ได้เหมือนเรียกฟังก์ชันทั่วไป **ทำไมต้องใช้ Function Expression** — เพราะฟังก์ชันถูกเก็บเป็นตัวแปร เราจึงสามารถเลือกได้ว่าตัวแปรนี้จะเก็บฟังก์ชันไหน เปลี่ยนฟังก์ชันภายหลัง หรือส่งต่อเป็น argument ให้ฟังก์ชันอื่นได้ แนวคิดนี้สำคัญมากก่อนจะไปถึง callback, arrow function, และ closure ในบทหลัง
ต้องประกาศก่อนเรียกใช้ — ต่างจาก Function Declaration
Function Declaration ถูก hoist จึงเรียกก่อนบรรทัดประกาศได้ แต่ Function Expression ต้องรอให้ตัวแปรได้รับฟังก์ชันก่อน จึงค่อยเรียกใช้ได้ เพราะเราใช้ `const` เก็บฟังก์ชัน ตัวแปรจะยังไม่พร้อมจนกว่าบรรทัด `const fn = function() { ... }` จะถูกรัน
| เรื่องที่เทียบ | Function Declaration | Function Expression |
|---|---|---|
| syntax | function greet() {} | const greet = function() {} |
| เรียกก่อนประกาศ | ได้ | ไม่ได้ |
| สิ่งที่เราเรียกใช้ | ชื่อฟังก์ชัน | ชื่อตัวแปรที่เก็บฟังก์ชัน |
| เหมาะกับ | ฟังก์ชันหลักที่ประกาศชัดเจน | ฟังก์ชันที่อยากเก็บไว้ในตัวแปรหรือเลือกใช้ภายหลัง |
เรียก `double()` ก่อนประกาศ → ReferenceError เพราะตัวแปร `double` ยังไม่ได้รับค่า
console.log(double(4)); // ❌ ReferenceError
const double = function(number) {
return number * 2;
};สาเหตุไม่ใช่เพราะ keyword `function` ใช้ไม่ได้ แต่เพราะตัวแปร `double` ยังไม่ได้รับค่าฟังก์ชันในตอนที่เราเรียกมัน **Anonymous vs Named Function Expression** — Function Expression มีได้ 2 แบบ คือแบบไม่มีชื่อฟังก์ชันด้านใน (anonymous) และแบบมีชื่อ (named) แบบ anonymous เจอบ่อยที่สุด แบบ named มักใช้เมื่อต้องการชื่อสำหรับ debug — ชื่อด้านในจะปรากฏใน stack trace หรือ console ทำให้ตามหาจุดผิดพลาดง่ายกว่า anonymous ซึ่งจะขึ้นแค่ `(anonymous)`
// anonymous — ไม่มีชื่อฟังก์ชันด้านใน
const greet = function(name) {
return "สวัสดี " + name;
};
// named — มีชื่อ sayHello ด้านใน จะเห็นชื่อนี้ใน error / debug
const greetNamed = function sayHello(name) {
return "สวัสดี " + name;
};
// ทั้งสองแบบทำงานเหมือนกัน เวลาเรียกใช้ให้เรียกผ่านชื่อตัวแปร
console.log(greet("มิน")); // "สวัสดี มิน"
console.log(greetNamed("มิน")); // "สวัสดี มิน"ใช้ Function Expression กับ parameter, default value, if/return
Function Expression ทำสิ่งเดียวกับฟังก์ชันแบบเดิมได้ทั้งหมด — รับ parameter, ตั้ง default value, ใช้ `if`, และ `return` ค่ากลับ ลองดูตัวอย่างจากง่ายไปหายาก:
parameter `amount` มีค่าเริ่มต้นเป็น `1` — เมื่อไม่ส่ง argument จะได้ค่า default
const announceProduct = function(name, amount = 1) {
return name + " จำนวน " + amount + " ชิ้น";
};
console.log(announceProduct("ปากกา")); // ปากกา จำนวน 1 ชิ้น
console.log(announceProduct("สมุด", 3)); // สมุด จำนวน 3 ชิ้นเช็กเงื่อนไขแล้ว return คนละค่า — return แรกที่เจอจะออกจากฟังก์ชันทันที
const checkPass = function(score) {
if (score >= 50) {
return "ผ่าน";
}
return "ไม่ผ่าน";
};
console.log(checkPass(72)); // ผ่าน
console.log(checkPass(35)); // ไม่ผ่านเช็ก `b === 0` ก่อนแล้ว return ออกจากฟังก์ชันทันที กรณีปกติค่อยคำนวณด้านล่าง
const divideSafe = function(a, b) {
if (b === 0) {
return "หารด้วยศูนย์ไม่ได้";
}
return a / b;
};
console.log(divideSafe(10, 2)); // 5
console.log(divideSafe(10, 0)); // หารด้วยศูนย์ไม่ได้เลือกเก็บฟังก์ชันตามเงื่อนไข — จุดแข็งของ Function Expression
เพราะฟังก์ชันถูกเก็บในตัวแปร เราจึงเลือกได้ว่าจะเก็บฟังก์ชันไหนไว้ แล้วค่อยเรียกใช้งานในขั้นถัดไป ลองดูตัวอย่าง: ใช้ `let` ประกาศตัวแปรไว้ก่อน แล้วค่อยเลือก assign ฟังก์ชันตามเงื่อนไข `if/else`
ตัวแปร `getMessage` จะเก็บฟังก์ชันคนละตัว ขึ้นอยู่กับว่า `isMorning` เป็น `true` หรือ `false`
let getMessage;
const isMorning = true;
if (isMorning) {
getMessage = function(name) {
return "สวัสดีตอนเช้า " + name;
};
} else {
getMessage = function(name) {
return "สวัสดีตอนเย็น " + name;
};
}
console.log(getMessage("ป่าน")); // สวัสดีตอนเช้า ป่านจุดสำคัญคือเราไม่ได้เรียกฟังก์ชันทันทีในทุกบรรทัด แต่เลือกก่อนว่าในตัวแปรนี้จะเก็บฟังก์ชันตัวไหน แล้วค่อยเรียกภายหลัง แนวคิดนี้คือพื้นฐานของ **callback** และ **higher-order function** ที่จะเรียนในบทต่อ ๆ ไป — ตอนนี้ขอให้จำ pattern การเลือก assign ฟังก์ชันไว้ก่อน