Việc bọc toàn bộ nội dung file JavaScript trong một hàm vô danh tự thi hành (IIFE - Immediately Invoked Function Expression):
(function() {
// Toàn bộ code file ở đây
})();
có mục đích cốt lõi là: Tạo một scope riêng (private scope) để cách ly biến/hàm, tránh ô nhiễm Global Scope (window/global).
Tại sao cần thiết? (Vấn đề Global Scope)
Trong JavaScript (trước ES6), biến khai báo bằng var ở cấp độ cao nhất (top-level) của script sẽ trở thành thuộc tính của Global Object (window trên trình duyệt, global trên Node.js).
// file1.js
var config = { apiUrl: "..." }; // window.config
// file2.js (load sau)
var config = { theme: "dark" }; // GHI ĐÈ window.config! Lỗi logic.
IIFE giải quyết vấn đề như thế nào?
// file1.js
(function() {
var config = { apiUrl: "..." }; // Chỉ tồn tại trong scope IIFE này
// Code sử dụng config...
})();
// file2.js
(function() {
var config = { theme: "dark" }; // Scope riêng, KHÔNG xung đột với file1
// Code sử dụng config...
})();
Mỗi file có "vùng đất riêng" (scope), biến config không còn là global.
Lợi ích chính
| Lợi ích | Giải thích |
|---|---|
| Cách ly biến (Encapsulation) | Biến cục bộ trong IIFE không truy cập được từ bên ngoài, tránh ghi đè/đọc nhầm. |
| Tránh xung đột tên (Namespace Collision) | Nhiều thư viện/script cùng load trên 1 trang không lo biến trùng tên. |
| Quản lý phụ thuộc (Dependency Management) | Truyền dependency vào IIFE như tham số: (function($, _) { ... })(jQuery, lodash); - bảo vệ khỏi thay đổi global. |
| Bảo mật thông tin (Information Hiding) | Logic nội bộ, key API, thuật toán bí mật không bị lộ ra global console. |
| Tối ưu Minification | Minifier có thể rename biến cục bộ an toàn (ngắn gọn) mà không lo ảnh hưởng global. |
Pattern phổ biến: Revealing Module Pattern
var MyLibrary = (function() {
// Private
var privateVar = 0;
function privateMethod() { ... }
// Public API
function publicMethod() { ... }
function anotherPublic() { ... }
return {
publicMethod: publicMethod,
anotherPublic: anotherPublic
};
})();
// Sử dụng
MyLibrary.publicMethod();
// MyLibrary.privateVar -> undefined (bảo vệ)
Trong thời đại ES6+ (Modern JS)
IIFE ít quan trọng hơn nhờ:
- ES Modules (import/export): Mỗi file tự động là một module, scope riêng, không ô nhiễm global. Chuẩn hiện đại, khuyên dùng.
- Block Scope (let/const): Biến không còn leo ra function scope.
- Bundler (Webpack, Rollup, Vite...): Tự động wrap mỗi module trong IIFE (hoặc module wrapper) khi bundle cho production.
Khi nào vẫn dùng IIFE?
- Code legacy (ES5), không dùng bundler/module.
- Script nhúng trực tiếp trong HTML (
<script>), không phải file module. - Polyfill, polyfill.io, script tracking (Google Analytics, Facebook Pixel...).
- Bookmarklet, userscript (Tampermonkey).
- Tạo scope tạm cho một khối code phức tạp trong function khác.
Tóm lại: Bọc file JS trong IIFE (function(){ ... })() nhằm tạo scope riêng, che giấu biến/hàm nội bộ, tránh xung đột global. Là pattern kinh điển (Module Pattern) trước thời ES Modules. Hiện nay ES Modules (import/export) là chuẩn thay thế tốt hơn.