Theo đặc tả ECMAScript, khai báo (declaration) và khởi tạo (initialization) là 2 bước riêng biệt trong vòng đời biến var.
Quy trình theo Spec
- Tạo biến (Creation): Khi Lexical Environment được khởi tạo (vào scope), biến
varđược tạo ra và gán giá trịundefined. - Khởi tạo (Initialization): Khi dòng code
var x = value;được thực thi (runtime), giá trịvalueđược gán cho biến.
Minh họa
console.log(x); // undefined (không lỗi)
var x = 10;
console.log(x); // 10
// Engine hiểu như sau:
// 1. Creation phase (hoisting): var x = undefined;
// 2. Execution phase:
// console.log(x); // undefined
// x = 10; // Initialization (gán giá trị)
// console.log(x); // 10
Khác biệt chính
| Đặc điểm | Khai báo (Declaration) | Khởi tạo (Initialization) |
|---|---|---|
| Thời điểm | Compile phase (tạo Lexical Env) | Runtime (khi dòng code chạy) |
| Hành động | Đăng ký biến trong scope, gán undefined | Gán giá trị thực từ biểu thức |
| Ví dụ | var x; | x = 10 (phần sau =) |
| Có thể tách biệt? | Có (hoisting tách khai báo khỏi gán) | Phải cùng dòng với khai báo hoặc sau |
let/const khác biệt
- Cũng bị hoisting (tạo binding trong scope) nhưng ở TDZ (Temporal Dead Zone).
- Truy cập trước dòng khai báo →
ReferenceError. let x;→ tạo binding, chưa khởi tạo (uninitialized).let x = 10;→ khởi tạo.const x = 10;→ bắt buộc khởi tạo ngay khi khai báo.
Function Declaration vs Expression
// Function Declaration: Hoisted hoàn toàn (tạo + khởi tạo function object)
foo(); // OK
function foo() { console.log("Hi"); }
// Function Expression (var): Chỉ khai báo var được hoisted
bar(); // TypeError: bar is not a function
var bar = function() { console.log("Hi"); };
Tại sao quan trọng?
- Hiểu
undefinedvsReferenceError. - Tránh bug dùng biến trước khi gán giá trị (logic sai dù không lỗi).
- Giải thích tại sao
function declarationgọi trước định nghĩa được. - Cơ sở của
let/constTDZ – thiết kế an toàn hơn.
Best Practice
- Dùng
constmặc định – buộc khởi tạo ngay, không gán lại. - Dùng
letkhi cần gán lại – khai báo ở đầu block. - Tránh
var– hoisting gây nhầm lẫn. - Khởi tạo biến ngay khi khai báo:
const x = compute()thay vì tách 2 dòng.