ความแตกต่างระหว่างฟังก์ชันปกติกับ Arrow Function ใน JavaScript และควรใช้ไวยากรณ์แบบไหนเมื่อไร
(jrsinclair.com)- การประกาศฟังก์ชันใน JavaScript มีได้หลายรูปแบบ เช่น การประกาศด้วยคีย์เวิร์ด
function, function expression, และ arrow function - function declaration ได้รับผลของ hoisting จึงสามารถอ้างอิงได้จากตำแหน่งใดก็ได้ในโค้ด
- Arrow function มีข้อดีคือ ไวยากรณ์ที่กระชับ แต่ก็มีความแตกต่างสำคัญ เช่น ไม่มีการ bind
this/arguments/super - constructor function, generator, method ไม่เหมาะกับการใช้ arrow function
- callback แบบง่ายหรือ anonymous function เหมาะกับ arrow function มากกว่า
Function Declarations, Function Expressions, and Arrow Functions
- ใน JavaScript สามารถนิยามฟังก์ชันได้ 3 แบบ คือ function declaration (statement), function expression, และ arrow function
- function declaration จะ bind ชื่อโดยตรง เช่น
function isVowel(chr) { ... }และ สามารถอ้างอิงได้จากทุกตำแหน่งในโค้ด (hoisting) อีกทั้งยังแสดงชื่อฟังก์ชันอย่างชัดเจนใน stack trace และระหว่าง debugging - function expression คือรูปแบบที่กำหนด anonymous function ให้กับตัวแปร เช่น
const takeWhile = function(predicate, arr) { ... } - function expression สามารถตั้งชื่อภายในได้เช่นกัน แต่ ชื่อนั้นจะไม่ถูก bind ในสโคปภายนอก และมักใช้เพื่อ ช่วยติดตามข้อผิดพลาดใน stack trace
Hoisting and Naming
- function declaration จะถูก hoist โดย JavaScript engine จึงยังทำงานได้แม้จะเรียกใช้ก่อนตำแหน่งที่ประกาศ
- anonymous function expression จะเรียกใช้ได้ก็ต่อเมื่อมีการกำหนดค่าให้ตัวแปรแล้วเท่านั้น
- เพื่อการ debug การ ตั้งชื่อฟังก์ชันอย่างชัดเจน อาจช่วยให้ stack trace อ่านง่ายขึ้น
Arrow Functions
- ไวยากรณ์สั้นและกระชับ: เขียนในรูป
(พารามิเตอร์) => { ... }โดยไม่ต้องใช้คีย์เวิร์ด function - เป็น anonymous function เสมอ (แต่สามารถกำหนดให้ตัวแปรเพื่อใช้เหมือนชื่อได้)
- ใช้ได้เฉพาะในฐานะ expression เท่านั้น ไม่ใช่ statement
- ไม่มีการ bind
this/arguments/super: ต่างจาก function declaration/expression ตรงที่จะ จับthisจากสโคปภายนอก - หากมีเพียง expression เดียว สามารถละวงเล็บปีกกาและ
returnได้ และถ้ามีพารามิเตอร์เดียวก็ละวงเล็บได้เช่นกัน - ใช้เป็น constructor ไม่ได้: arrow function ไม่สามารถเรียกด้วยคีย์เวิร์ด new และ ไม่ทำงานเป็น constructor function
- เป็น generator ไม่ได้: ใช้ yield ไม่ได้ และไม่สามารถสร้างเป็น generator function ได้
- ตัวอย่างโค้ด:
const sum = (a, b) => a + b; const square = x => x * x;
Practical Example: this, constructor และ generator
- มีตัวอย่างแสดงความแตกต่างของการจัดการ
thisระหว่างฟังก์ชันปกติกับ arrow function- เมื่อใช้เป็นเมธอดภายในอ็อบเจ็กต์ ฟังก์ชันปกติจะมี
thisชี้ไปที่ตัวอ็อบเจ็กต์เอง แต่ arrow function จะชี้ไปที่undefinedหรือthisจากสโคปภายนอก
- เมื่อใช้เป็นเมธอดภายในอ็อบเจ็กต์ ฟังก์ชันปกติจะมี
- หากนิยาม constructor function ด้วย arrow function จะเกิด TypeError
- generator function จำเป็นต้องใช้ไวยากรณ์
function*เท่านั้น
ควรเลือกใช้ไวยากรณ์ฟังก์ชันแบบไหนเมื่อไร?
- ต้องการ generator (ใช้
yield) → ใช้function* - ต้องใช้
this→ ใช้คีย์เวิร์ดfunctionหรือ class method - ต้องการ hoisting หรืออยากให้โค้ดระดับบนอ่านง่าย → ใช้ function declaration
- หากไม่เข้าข่ายข้างต้น → เขียนด้วย arrow function จะกระชับกว่า
บทสรุป
- ฟังก์ชันใน JavaScript ควรเลือกไวยากรณ์ตามจุดประสงค์การใช้งาน ความจำเป็นของ
thisและการเป็น constructor/generator - callback ทั่วไปหรือฟังก์ชันง่าย ๆ เหมาะกับ arrow function มากที่สุด
- object method/constructor/generator จำเป็นต้องใช้ไวยากรณ์
function - หากต้องการ hoisting หรือความยืดหยุ่นในลำดับการประกาศ function declaration จะได้เปรียบ
3 ความคิดเห็น
เรื่องความมีหรือไม่มี prototype ก็สำคัญพอๆ กับพื้นฐาน ...
รวมถึงวิธีอ้างอิงของฟังก์ชันลำดับสูงที่ถูกสร้างขึ้นด้วย ...
const a = (a: () => null): (() => () => null) =>() => a
() => ❤️