22 điểm bởi GN⁺ 2025-07-15 | 3 bình luận | Chia sẻ qua WhatsApp
  • Khai báo hàm trong JavaScript có thể được thực hiện theo nhiều cách như dùng từ khóa function, biểu thức hàm, và hàm mũi tên
  • Khai báo hàm được áp dụng hoisting, nên có thể được tham chiếu ở bất kỳ vị trí nào trong mã
  • Hàm Arrow (mũi tên) có ưu điểm là cú pháp ngắn gọn, nhưng có những khác biệt quan trọng như không có ràng buộc this/arguments/super
  • Hàm tạo, generator, method không phù hợp để dùng hàm mũi tên
  • Với callback đơn giản hoặc hàm ẩn danh, hàm mũi tên phù hợp hơn

Function Declarations, Function Expressions, and Arrow Functions

  • Trong JavaScript, có thể định nghĩa hàm theo ba cách: khai báo hàm (statement), biểu thức hàm (expression), và hàm mũi tên (arrow function)
  • Khai báo hàm gắn trực tiếp tên như function isVowel(chr) { ... }, và có thể được tham chiếu ở bất kỳ đâu trong mã (hoisting). Trong stack trace và khi debug, tên hàm cũng được hiển thị rõ ràng
  • Biểu thức hàm có dạng gán một hàm ẩn danh cho biến như const takeWhile = function(predicate, arr) { ... }
  • Biểu thức hàm cũng có thể có tên nội bộ, nhưng tên đó không được ràng buộc vào scope bên ngoài, mà chủ yếu được dùng để lần vết lỗi trong stack trace

Hoisting and Naming

  • Câu lệnh khai báo hàm được JavaScript engine hoist, nên vẫn hoạt động ngay cả khi được gọi trước chỗ khai báo
  • Biểu thức hàm ẩn danh chỉ có thể được gọi sau khi biến đã được gán
  • Để debug tốt hơn, việc đặt tên hàm một cách tường minh có thể có lợi trong stack trace

Arrow Functions

  • Cú pháp ngắn và gọn: viết theo dạng (tham số) => { ... } mà không cần từ khóa function
  • Luôn là hàm ẩn danh (dù có thể gán vào biến để dùng như một cái tên)
  • Chỉ có thể dùng như biểu thức (expression), không phải câu lệnh (statement)
  • Không có ràng buộc this/arguments/super: khác với khai báo hàm/biểu thức hàm, nó sẽ bắt giữ this của scope bên ngoài
  • Với biểu thức đơn, có thể bỏ dấu ngoặc nhọn và return, và nếu chỉ có 1 tham số thì cũng có thể bỏ ngoặc
  • Không thể dùng làm constructor: hàm mũi tên không thể được gọi với từ khóa new, và không hoạt động như hàm tạo
  • Không thể là generator: không dùng được yield, và không thể tạo thành generator function
  • Ví dụ mã:
    const sum = (a, b) => a + b;  
    const square = x => x * x;  
    

Practical Example: this, constructor, và generator

  • Có ví dụ minh họa sự khác biệt giữa hàm thông thường và hàm mũi tên trong cách xử lý this
    • Khi dùng làm method trong object, hàm thông thường sẽ có this trỏ tới chính object đó, còn hàm mũi tên sẽ trỏ tới undefined hoặc this của scope bên ngoài
  • Nếu định nghĩa hàm tạo bằng hàm mũi tên thì sẽ phát sinh TypeError
  • Generator function bắt buộc phải dùng cú pháp function*

Nên chọn cú pháp hàm nào khi nào?

  • Cần generator (dùng yield) → dùng function*
  • Cần sử dụng this → dùng từ khóa function hoặc method của class
  • Cần hoisting hoặc muốn tăng khả năng đọc ở cấp độ cao hơn → dùng câu lệnh khai báo hàm
  • Nếu không thuộc các trường hợp trên → hàm mũi tên sẽ có lợi thế hơn nhờ sự ngắn gọn

Kết luận

  • Với hàm trong JavaScript, nên chọn cú pháp dựa trên mục đích sử dụng, việc có cần this hay không, và có phải constructor/generator hay không
  • Với callback thường ngày / hàm đơn giản, hàm mũi tên là lựa chọn tốt nhất
  • Với method của object / constructor / generator, cần dùng cú pháp function
  • Nếu cần hoisting hoặc sự linh hoạt về thứ tự khai báo, thì câu lệnh khai báo hàm sẽ có lợi hơn

3 bình luận

 
ng0301 2025-07-15

Không chỉ là bản chất mà còn là việc có hay không có prototype...
Cả cách tham chiếu của hàm bậc cao được tạo ra cũng vậy...

 
bichi 2025-07-15
const a = (a: () => null): (() => () => null) =>() => a
 
bichi 2025-07-15

() => ❤️