Tản mạn về Function Declaration và Function Expression
Bài đăng này đã không được cập nhật trong 8 năm
JavaScript là ngôn ngữ có cú pháp sáng sủa, dễ học dễ dùng và cực kỳ thông dụng. Tuy nhiên dùng được không hẳn đã hiểu rõ bản chất của nó, bài viết này mình sẽ nói qua về 2 khái niệm Function Declaration (FD)
và Function Expression (FE)
, mình tin rằng cũng khá nhiều người không rõ và sẽ xảy ra lỗi khi sử dụng chúng.
1.Đặt vấn đề
Những điều nhìn có vẻ giản dị như thế này lại có thể gây ra những nhầm lẫn không tưởng, dưới đây là vài ví dụ, bạn hãy tự nhẩm kết quả rồi chạy thử xem có đúng không nhé.
// Sau mỗi lần thử nên end session đang thử đi và tạo lại để kết quả được chuẩn nhất nhé.
function foo(){
function bar() {
return 3;
}
return bar();
function bar() {
return 8;
}
}
alert(foo());
function foo(){
var bar = function() {
return 3;
};
return bar();
var bar = function() {
return 8;
};
}
alert(foo());
alert(foo());
function foo(){
var bar = function() {
return 3;
};
return bar();
var bar = function() {
return 8;
};
}
function foo(){
return bar();
var bar = function() {
return 3;
};
var bar = function() {
return 8;
};
}
alert(foo());
Nếu bạn test thử mà đúng hết thì chắc là chẳng cần đọc tiếp đâu . Bên dưới mình sẽ không chỉ ra nguyên nhân bạn có thể sai hay diễn giải từng dòng code để ra kết quả, mình sẽ chỉ đưa ra khái niệm, bản chất và đặc điểm của chúng. Ngoài bài biết này bạn cũng cần phải hiểu về khái niệm hoisting
để đưa ra kết quả đúng.
2.Khái niệm
Khai báo
Về khai báo, FD bắt buộc phải bắt đầu với function
ở đầu dòng lệnh còn FE thì ngược lại.
Ví dụ
function a(){} // FD
var foo = function(){...} //FE
(foo(){...})(); //FE
Thêm nữa, cấu trúc của FD và FE khác nhau ở chỗ FE thì không yêu cầu tên function, có hay không cũng được. Không đặt tên cho function kể ra cũng khá tiện lợi cho mình, nhanh gọn khỏi cần suy nghĩ tên hay sợ trùng với function khác gây hiểu lầm khi đọc lại code, nhưng tùy trường hợp chúng ta vẫn cần đặt tên cho chúng. Ví dụ như sau người khác đọc lại không biết function này làm cái gì hay khi cần gọi đệ quy thì cũng chẳng có cái gì mà gọi. Nói chung là nếu code đơn giản thì bỏ tên đi, còn nếu thực hiện tác vụ gì đó thì cứ dí cái tên vào, trước sau gì cũng cần, không thưà đâu. Đọc code càng rõ ràng thì thằng đọc code càng khen thằng viết code =]] Ví dụ:
// Không cần tên
setTimeout( function(){
console.log("I waited 1 second!");
}, 1000 );
// Thêm vào cho rõ ràng
var x = function generateHoooman(){...}
Bản chất Còn về bản chất FD và FE khác nhau ở vùng scope ảnh hưởng. Với FD, tên của function sẽ hiện hữu ở scope của nó và scope cha của nó (Nơi nó được tạo ra), còn với FE, tên của function (Nếu có) sẽ chỉ hiện hưũ ở scope của nó, và nó sẽ không tồn tại ngoài scope cha. Một điều quan trọng nữa, FE sẽ không được hoisting như function bình thường. Demo :
// Chạy ngon
console.log(foo());
function foo() {};
// Lỗi
console.log(foo());
var a = function foo() {};
Kết luận
Đến đây thì bạn có thể xem lại những đoạn code trên và nhẩm lại, hi vọng bạn sẽ tính lại đúng sau khi nắm được sự khác nhau giữa FD và FE cũng như cách dùng chúng. Để nắm rõ hơn về chúng, bạn có thể tham khảo ở đây. You Don't Know JS: Scope & Closures Hi vọng sau bài viết này, bạn sẽ có thêm động lực để đào sâu vào tìm hiểu bản chất của vấn đề. Vì bây giờ có thể bạn code bình thường, dùng bình thường, nhưng đến khi có bug thì chắc chỉ có đi nhờ support chứ cũng khó mà debug được. Bài viết dựa trên vốn kiến thức eo hẹp của cá nhân nên sẽ không tránh khỏi sai sót, mong nhận được những đóng góp tích cực của mọi người để mình hoàn hiện bài viết cũng như đính chính lại kiến thức của bản thân cho đúng đắn.
All rights reserved