Quay trở lại cuối những năm 90 – khi tôi học JavaScript – chúng tôi được dạy viết hàm “Xin chào thế giới” bằng cách sử dụng một tuyên bố chức năng. Như thế này…
function helloWorld() {
return ‘Hello World!’;
}
Ngày nay, có vẻ như tất cả những đứa trẻ tuyệt vời đang viết chức năng “Xin chào thế giới” như thế này…
const helloWorld = () => 'Hello World!';
Đây là một biểu thức hàm trong ES2015 JavaScript và nó hấp dẫn kinh khủng. Thật đẹp khi nhìn vào. Đó là tất cả một dòng. Vì vậy, ngắn gọn. Thật đáng yêu.
Nó sử dụng chức năng mũi tên, một trong những tính năng phổ biến nhất của ES2015.
Khi tôi lần đầu tiên nhìn thấy điều này, tôi đã như thế này:

Vì vậy, sau gần 20 năm sử dụng JavaScript và sau khi sử dụng ES2015 cho một số dự án, đây là cách tôi sẽ viết hàm “Xin chào thế giới” ngày hôm nay:
function helloWorld() {
return ‘Hello World!’;
}
Bây giờ tôi đã chỉ cho bạn cách mới, tôi chắc chắn rằng bạn sẽ khó có thể đứng yên khi nhìn vào mã trường học cũ ở trên.
Toàn bộ ba dòng chỉ cho một chức năng nhỏ đơn giản! Tất cả những nhân vật phụ đó!
Tôi biết bạn đang nghĩ gì…

Tôi thực sự yêu thích chức năng mũi tên. Nhưng khi tôi cần khai báo một hàm cấp cao nhất trong mã của mình, tôi vẫn sử dụng một câu lệnh hàm kiểu cũ.
Câu nói này của “Chú Bob” Martin giải thích tại sao:
“…tỷ lệ thời gian đọc so với viết là hơn 10 trên 1. Chúng tôi liên tục đọc mã cũ như một phần trong nỗ lực viết mã mới.
Vì tỷ lệ này quá cao nên chúng tôi muốn việc đọc mã trở nên dễ dàng ngay cả khi nó khiến việc viết khó hơn.”
— Robert C. Martin
Clean Code: Sổ tay thủ công phần mềm linh hoạt
Các câu lệnh hàm có hai ưu điểm rõ ràng so với các biểu thức hàm:
Lợi thế #1: Mục đích rõ ràng
Khi quét qua hàng nghìn dòng mã mỗi ngày, thật hữu ích khi có thể tìm ra ý định của lập trình viên một cách nhanh chóng và dễ dàng nhất có thể.
Hãy xem này:
const maxNumberOfItemsInCart = ...;
Bạn đọc tất cả những ký tự đó và bạn vẫn không biết liệu dấu chấm lửng có đại diện cho một chức năng hay một số giá trị khác hay không. Nó có thể là:
const maxNumberOfItemsInCart = 100;
…hoặc nó có thể dễ dàng là:
const maxNumberOfItemsInCart = (statusPoints) => statusPoints * 10;
Nếu bạn sử dụng một câu lệnh chức năng, sẽ không có sự mơ hồ như vậy.
Nhìn vào:
const maxNumberOfItemsInCart = 100;
…đấu với:
function maxNumberOfItemsInCart(statusPoints) {
return statusPoints * 10;
}
Ý định rõ ràng ngay từ đầu dòng.
Nhưng có thể bạn đang sử dụng trình chỉnh sửa mã có một số manh mối về mã màu. Có thể bạn là một người đọc tốc độ. Có lẽ bạn không nghĩ đó là một vấn đề lớn.
Tôi nghe bạn. Sự căng thẳng trông vẫn khá gợi cảm.
Trên thực tế, nếu đây là lý do duy nhất của tôi, tôi có thể đã tìm ra cách thuyết phục bản thân rằng đó là một sự đánh đổi xứng đáng.
Nhưng no la không phải lý do duy nhất của tôi…
Ưu điểm #2: Thứ tự khai báo == thứ tự thực hiện
Lý tưởng nhất là tôi muốn khai báo mã của mình ít nhiều theo thứ tự mà tôi mong đợi nó sẽ được thực thi.
Đây là công cụ hiển thị đối với tôi: bất kỳ giá trị nào được khai báo bằng từ khóa const đều là không thể truy cập cho đến khi thực hiện đạt được nó.

Cảnh báo đúng: Tôi chuẩn bị đi tất cả, “Giáo sư JavaScript” với bạn. Điều duy nhất bạn cần hiểu trong tất cả các biệt ngữ dưới đây là bạn không thể sử dụng const cho đến khi bạn khai báo nó.
Đoạn mã sau sẽ báo lỗi:
sayHelloTo(‘Bill’);
const sayHelloTo = (name) => `Hello ${name}`;
Điều này là do, khi công cụ JavaScript đọc mã, nó sẽ trói buộc “sayHelloTo”, nhưng nó sẽ không khởi tạo nó.
Tất cả các khai báo trong JavaScript đều bị ràng buộc sớm, nhưng chúng được khởi tạo khác nhau.
Nói cách khác, Javascript ràng buộc phần khai báo của “sayHelloTo” — đọc nó trước và tạo một khoảng trống trong bộ nhớ để giữ giá trị của nó – nhưng nó không bộ “sayHelloTo” với bất cứ thứ gì cho đến khi nó đạt được nó trong thời gian chấp hành.
Khoảng thời gian giữa “sayHelloTo” bị ràng buộc và “sayHelloTo” được khởi tạo được gọi là vùng chết tạm thời (TĐZ).
Nếu bạn đang sử dụng ES2015 trực tiếp trong trình duyệt (trái ngược với việc chuyển mã xuống ES5 bằng thứ gì đó như Babel), đoạn mã sau thực sự cũng gây ra lỗi:
if(thing) {
console.log(thing);
}
const thing = 'awesome thing';
Đoạn mã trên, được viết bằng “var” thay vì “const”, sẽ không phải ném một lỗi vì vars được khởi tạo như không xác định khi chúng bị ràng buộc, trong khi consts hoàn toàn không được khởi tạo tại thời điểm ràng buộc. Nhưng tôi lạc đề…
Các câu lệnh chức năng không gặp phải vấn đề TDZ này. Sau đây là hoàn toàn hợp lệ:
sayHelloTo(‘Bill’);
function sayHelloTo(name) {
return `Hello ${name}`;
}
Điều này là do các câu lệnh hàm được khởi tạo ngay khi chúng bị ràng buộc – trước bất kỳ mã nào được thực thi.
Vì vậy, bất kể khi nào bạn khai báo hàm, nó sẽ có sẵn cho phạm vi từ vựng ngay khi mã bắt đầu thực thi.

Những gì tôi vừa mô tả ở trên buộc chúng ta phải viết mã có vẻ lộn ngược. Chúng ta phải bắt đầu với chức năng cấp thấp nhất và tiến dần lên.
Bộ não của tôi không hoạt động theo cách đó. Tôi muốn bối cảnh trước các chi tiết.
Hầu hết mã được viết bởi con người. Vì vậy, điều hợp lý là thứ tự hiểu biết của hầu hết mọi người gần như tuân theo thứ tự thực thi của hầu hết mã.
Trên thực tế, sẽ rất tuyệt nếu chúng tôi có thể cung cấp một bản tóm tắt nhỏ về API của chúng tôi ở đầu mã của chúng tôi? Với các câu lệnh hàm, chúng ta hoàn toàn có thể làm được.
Kiểm tra mô-đun giỏ hàng (hơi giả tạo) này…
export {
createCart,
addItemToCart,
removeItemFromCart,
cartSubTotal,
cartTotal,
saveCart,
clearCart,
}
function createCart(customerId) {...}
function isValidCustomer(customerId) {...}
function addItemToCart(item, cart) {...}
function isValidCart(cart) {...}
function isValidItem(item) {...}
...
Với các biểu thức hàm, nó sẽ giống như…
...
const _isValidCustomer = (customerId) => ...
const _isValidCart = (cart) => ...
const _isValidItem = (item) => ...
const createCart = (customerId) => ...
const addItemToCart = (item, cart) => ...
...
export {
createCart,
addItemToCart,
removeItemFromCart,
cartSubTotal,
cartTotal,
saveCart,
clearCart,
}
Hãy tưởng tượng đây là một mô-đun lớn hơn với nhiều chức năng nhỏ bên trong. Bạn thích cái nào?
Có những người sẽ lập luận rằng việc sử dụng thứ gì đó trước khi bạn tuyên bố nó là không tự nhiên và có thể gây ra những hậu quả không lường trước được. Thậm chí có những người cực kỳ thông minh đã nói những điều như vậy.
Đó chắc chắn là một ý kiến - không phải là sự thật – rằng cách này tốt hơn cách kia.
Nhưng nếu bạn hỏi tôi: Mã là giao tiếp. Mã tốt kể một câu chuyện.
Tôi sẽ để các trình biên dịch và bộ chuyển mã, bộ rút gọn và bộ làm xấu xử lý việc tối ưu hóa mã cho máy.
Tôi muốn tối ưu hóa mã của mình cho sự hiểu biết của con người.
Tuy nhiên, những chức năng mũi tên đó thì sao?
Đúng. Vẫn gợi cảm và vẫn tuyệt vời.
Tôi thường sử dụng các hàm mũi tên để chuyển một hàm nhỏ làm giá trị cho một hàm bậc cao hơn. Tôi sử dụng các chức năng mũi tên với lời hứa, với bản đồ, với bộ lọc, với giảm thiểu. Họ là những con ong đầu gối, bạn bè của tôi!
Vài ví dụ:
const goodSingers = singers.filter((singer) => singer.name !== 'Justin Bieber');
function tonyMontana() {
return getTheMoney()
.then((money) => money.getThePower())
.then((power) => power.getTheWomen());
}
Tôi đã sử dụng một vài tính năng JavaScript mới khác trong bài viết này. Nếu bạn muốn tìm hiểu thêm về tiêu chuẩn JavaScript mới nhất (ES2015) và tất cả các tính năng thú vị mà nó cung cấp, bạn sẽ nhận được hướng dẫn bắt đầu nhanh của tôi miễn phí.
Mục tiêu của tôi là luôn giúp đỡ càng nhiều nhà phát triển càng tốt, nếu bạn thấy bài viết này hữu ích, vui lòng nhấn nút ❤ (khuyến nghị) để những người khác sẽ thấy nó. Cảm ơn!