Trong JavaScript, nếu gán giá trị cho biến chưa từng khai báo (không có var, let, const), biến đó sẽ tự động trở thành biến toàn cục (global variable) – gắn vào object window (trong browser) hoặc global (Node.js).
Ví dụ minh họa
function demo() {
rank = 5; // Tự tạo window.rank = 5 (global)
var points = 10; // Local trong hàm
}
demo();
console.log(rank); // 5 - truy cập được global
console.log(points); // ReferenceError - points là local
Ví dụ chi tiết từ bài gốc
var rank = 5;
points = 50; // Tự tạo global points
marks = 300; // Tự tạo global marks
(function() {
points = 100; // Ghi đè global points
var rank = 4; // Tạo local rank mới (shadowing)
var marks = 900; // Tạo local marks mới
console.log(rank); // 4 (local)
console.log(points); // 100 (global đã ghi đè)
console.log(marks); // 900 (local)
})();
console.log(rank); // 5 (global gốc)
console.log(points); // 100 (global bị ghi đè)
console.log(marks); // 300 (global gốc)
Tại sao đây là thực hành xấu (Anti-pattern)?
| Vấn đề | Hậu quả |
|---|---|
| Nhiễm global namespace | Xung đột biến, library khác ghi đè |
| Khó debug | Không biết biến được tạo ở đâu |
| Strict Mode cấm | "use strict" ném ReferenceError |
| Rò rỉ bộ nhớ | Global không bao giờ bị GC dọn |
| Khó test | State chung giữa các test case |
Strict Mode ngăn chặn
"use strict";
x = 10; // ReferenceError: x is not defined
Cách đúng: Luôn khai báo biến
// ES6+ (khuyến nghị)
const PI = 3.14; // Hằng số
let count = 0; // Biến thay đổi
var legacy = "old"; // Chỉ cho code cũ
// Module pattern / IIFE để cách ly scope
(function() {
let privateVar = "safe";
})();
Phát hiện biến global vô tình
- ESLint rule:
no-implicit-globals,no-undef. - Chrome DevTools: Console gõ tên biến – nếu hiện giá trị mà không khai báo → global rác.
- Chạy trong
"use strict"để bắt lỗi sớm.
Khi nào có thể chấp nhận?
Hầu như không bao giờ trong code production. Chỉ có thể thấy trong:
- Code legacy cũ (trước ES5 strict mode).
- Bookmarklet, userscript nhỏ.
- REPL console để test nhanh.