Hoisting trong JavaScript là một cơ chế mặc định mà JavaScript “di chuyển” (hoist) các khai báo biến và hàm lên đầu phạm vi của chúng trong quá trình biên dịch, trước khi code thực thi. Điều này có nghĩa là các biến và hàm có thể được sử dụng trước khi chúng được khai báo trong code.
Cách hoạt động của hoisting:
- Hoisting biến:
- Trong trường hợp của biến, chỉ có khai báo được hoisted, không phải giá trị khởi tạo.
- Ví dụ:
console.log(x); // undefined var x = 5;
Trong đoạn code trên, biến
x
được hoisted lên đầu phạm vi và khởi tạo với giá trịundefined
. Khiconsole.log(x)
được gọi, giá trị củax
làundefined
chứ không phải5
, vì giá trị5
chỉ được gán sau đó.
- Hoisting với
let
vàconst
:- Với
let
vàconst
, biến cũng được hoisted nhưng không thể truy cập trước khi chúng được khai báo rõ ràng trong “temporal dead zone” (vùng chết tạm thời). Việc sử dụng biến trước khi khai báo sẽ gây ra lỗi. - Ví dụ:
console.log(y); // ReferenceError: Cannot access 'y' before initialization let y = 10;
- Với
- Hoisting hàm:
- Với các hàm khai báo (function declaration), cả phần khai báo và định nghĩa của hàm đều được hoisted. Do đó, bạn có thể gọi hàm trước khi nó được định nghĩa trong code.
- Ví dụ:
greet(); // Hello! function greet() { console.log("Hello!"); }
Trong đoạn code trên, hàm
greet()
có thể được gọi trước khi nó được định nghĩa.
- Hoisting hàm ẩn danh (function expression):
- Đối với hàm ẩn danh hoặc arrow function gán cho biến, chỉ có phần khai báo biến được hoisted chứ không phải phần định nghĩa hàm. Điều này sẽ gây lỗi nếu bạn gọi hàm trước khi định nghĩa.
- Ví dụ:
sayHello(); // TypeError: sayHello is not a function var sayHello = function() { console.log("Hello!"); }
Chi tiết về phạm vi hoisting:
- Phạm vi toàn cục:
- Khi bạn khai báo biến hoặc hàm trong phạm vi toàn cục (bên ngoài bất kỳ hàm nào), các khai báo này sẽ được hoisted lên đầu của phạm vi toàn cục.
- Ví dụ:
console.log(globalVar); // undefined var globalVar = 10;
- Phạm vi hàm:
- Khi bạn khai báo biến hoặc hàm bên trong một hàm, các khai báo này sẽ được hoisted lên đầu phạm vi của hàm đó.
- Ví dụ:
function test() { console.log(localVar); // undefined var localVar = 20; } test();
- Phạm vi khối (Block Scope):
- Đối với các khai báo sử dụng
let
vàconst
, hoisting vẫn xảy ra, nhưng các biến này không thể được truy cập trước khi chúng được khai báo do nằm trong “Temporal Dead Zone” (TDZ). Điều này có nghĩa là mặc dù chúng được hoisted lên, nhưng chúng không có giá trị cho đến khi dòng khai báo được thực thi.
- Đối với các khai báo sử dụng
Sự khác biệt giữa let
, var
, và const
trong JavaScript liên quan đến hoisting và temporal dead zone (TDZ)
1. Hoisting
- Tất cả các biến được khai báo bằng
var
,let
, vàconst
đều được hoisted lên đầu phạm vi của chúng. - Điều này có nghĩa là khi mã được biên dịch, JavaScript sẽ biết về sự tồn tại của các biến này, nhưng cách mà chúng được khởi tạo và truy cập khác nhau.
2. Khởi tạo
var
:- Biến được khai báo bằng
var
sẽ được hoisted và khởi tạo với giá trịundefined
ngay khi hoisting diễn ra. - Bạn có thể truy cập biến này trước khi nó được khai báo trong mã mà không gặp lỗi, nhưng giá trị của nó sẽ là
undefined
.Ví dụ:console.log(x); // Output: undefined var x = 10; console.log(x); // Output: 10
- Biến được khai báo bằng
let
và const
:
- Biến được khai báo bằng
let
vàconst
cũng được hoisted, nhưng chúng không được khởi tạo cho đến khi dòng mã mà chúng được khai báo được thực thi. - Nếu bạn cố gắng truy cập biến
let
hoặcconst
trước khi nó được khai báo, bạn sẽ gặp lỗiReferenceError
do nó nằm trong temporal dead zone.Ví dụ:console.log(y); // ReferenceError: Cannot access 'y' before initialization let y = 20; console.log(y); // Output: 20 console.log(z); // ReferenceError: Cannot access 'z' before initialization const z = 30; console.log(z); // Output: 30
Kết luận:
var
: Hoisted và khởi tạo với giá trịundefined
. Có thể truy cập trước khi khai báo mà không gặp lỗi.let
vàconst
: Hoisted nhưng không khởi tạo ngay lập tức. Không thể truy cập trước khi khai báo, và sẽ gặp lỗiReferenceError
nếu bạn cố gắng làm như vậy.- Temporal Dead Zone (TDZ): Vùng mà biến
let
vàconst
chưa được khởi tạo và không thể truy cập cho đến khi đến dòng khai báo.

Dương Trần Hà, hiện mình đang là kỹ công nghệ phần mềm và cũng là giám đốc thành lập công ty DTH Solutions. Mình có nhiều năm kinh nghiệm, kiến thức chuyên môn lập trình, nodejs, nestjs, laravel, yii2, reactjs, nextjs. Mình đã phát triển rất nhiều dự án thực tế cho doanh nghiệp, cơ quan. Mình đã đạt được một số thành công nhỏ, đồng thời mình vẫn đang tiếp tục học tập để trau dồi kiến thức mỗi ngày. Mình rất yêu thích công nghệ, đam mê chia sẻ những kiến thức, thông tin hữu ích cho mọi người.