Dấu chấm than ! (hoặc +, -, ~, void) đặt ngay trước từ khóa function được gọi là Leading Bang (Dấu chấm than dẫn đầu) hoặc Unary Operator Trick. Mục đích: Ép trình phân tích (parser) coi định nghĩa hàm là một "Expression" (Biểu thức) thay vì "Statement" (Câu lệnh), từ đó cho phép gọi hàm ngay lập tức (IIFE).
Cú pháp
!function() {
// code
}();
// Tương đương các toán tử unary khác:
+function() { ... }();
-function() { ... }();
~function() { ... }();
void function() { ... }();
Cơ chế hoạt động
function() { ... }ở đầu dòng -> Parser hiểu là Function Declaration (bắt buộc có tên, không gọi ngay được).- Toán tử unary (
!,+...) đứng trước -> Parser buộc phải đánh giá toán hạng của nó -> Toán hạng phải là Expression. function() { ... }lúc này được xem là Function Expression (giá trị).- Cặp ngoặc
()cuối cùng -> Gọi hàm (Invocation) ngay lập tức.
Ví dụ
// 1. Leading Bang (!) - Trả về boolean phủ định kết quả hàm
!function(name) {
console.log("Hello " + name);
return "OK";
}("An");
// Output: "Hello An"
// Biểu thức toàn bộ trả về: !"OK" = false
// 2. Leading Plus (+) - Trả về số (ép kiểu kết quả)
+function(a, b) {
return a + b;
}(2, 3);
// Output: 5 (number)
// 3. Void - Luôn trả về undefined (an toàn, rõ ràng ý đồ)
void function() {
console.log("Chạy ngay, không quan tâm kết quả");
}();
So sánh các toán tử Unary cho IIFE
| Toán tử | Ký tự | Giá trị trả về của toàn bộ biểu thức IIFE | Phổ biến |
|---|---|---|---|
| Logical NOT | ! | Boolean (phủ định kết quả hàm) | Rất phổ biến (jQuery, Bootstrap, libs cũ) |
| Unary Plus | + | Number (ép kiểu kết quả hàm) | Phổ biến (minify ngắn gọn) |
| Unary Negation | - | Number (âm kết quả hàm) | Ít dùng |
| Bitwise NOT | ~ | Number (bitwise not kết quả) | Rất ít |
| Void | void | undefined (Luôn) | Khuyên dùng cho rõ ràng ý đồ "không dùng kết quả" |
| Parentheses | ( ) | Giá trị gốc của hàm | Chuẩn Crockford, dễ đọc nhất |
Khi nào dùng cái nào?
- Viết code thủ công, team dev: Dùng
(function(){})()(Crockford style) - Dễ đọc, rõ ràng, trả về giá trị gốc. - Minifier / Build tool: Thường chuyển sang
!function(){}()hoặc+function(){}()để tiết kiệm 1-2 byte. - Bookmarklet / Userscript:
void function(){}()an toàn nhất (tránh pollute global scope bằng giá trị trả về). - Module pattern cần trả về API: Phải dùng
(function(){ return {...} })()hoặc(function(){ ... })()(không unary operator).
⚠️ Lưu ý
- Luôn kết thúc IIFE bằng
;nếu dòng sau bắt đầu bằng(,[,/,+,-. - Arrow function không dùng được unary operator trick này:
!() => {}()lỗi cú pháp. Dùng(() => {})(). - Trong ES6+, ưu tiên ES Modules (import/export) thay vì IIFE.
Tóm lại: !function(){}() (Leading Bang) là một trong các cách viết IIFE bằng toán tử unary để ép parser chấp nhận function expression và gọi ngay. void an toàn nhất cho giá trị trả về, () dễ đọc nhất, !/+ ngắn gọn cho minify.