Tìm Hiểu Về Hoisting trong JavaScript

3 min read

Hoisting là một trong những khái niệm quan trọng mà bất kỳ nhà phát triển nào sử dụng JavaScript hoặc các framework liên quan đều nên nắm vững. Bạn có bao giờ thắc mắc tại sao có thể gọi hàm hoặc truy cập biến trước khi chúng được khai báo chưa? Nếu có, chào mừng bạn đến với thế giới của JavaScript Hoisting!

Hoisting là gì?

Đây là một trong những câu hỏi phổ biến và câu trả lời thường thấy là:

“Tất cả các khai báo biến và hàm sẽ được đưa lên đầu.”

Tuy nhiên, đây là một hiểu lầm phổ biến. Trong JavaScript, không có gì thực sự được “di chuyển” lên đầu cả. Hãy cùng tìm hiểu chi tiết hơn!

Cách mã JavaScript được thực thi

JavaScript Engine thực thi mã của chúng ta qua hai giai đoạn:

  1. Giai đoạn khởi tạo (Creation Phase): Engine quét qua mã và cấp phát bộ nhớ cho các khai báo biến và hàm.
  2. Giai đoạn thực thi (Execution Phase): Engine thực thi mã theo từng dòng, thực hiện các phép gán giá trị và gọi hàm.

Hoisting với biến

Biến là một phần quan trọng trong mọi ngôn ngữ lập trình. Hiểu rõ cách khai báo và sử dụng biến giúp chúng ta tránh được các lỗi không mong muốn.

Ví dụ:

console.log('myName', myName); 
var myName = 'JavaScript';
console.log('myName', myName);

Khi chạy đoạn mã trên:

  • Dòng đầu tiên in ra undefined.
  • Dòng thứ hai in ra JavaScript.

Giải thích:
JavaScript tuân theo một vòng đời biến như sau:

  1. Khai báo (Declaration): var myName;
  2. Khởi tạo (Initialization): myName = 'JavaScript';
  3. Sử dụng (Utilization): console.log('myName', myName);

Trong giai đoạn khởi tạo, biến myName được khai báo với giá trị mặc định là undefined. Đến giai đoạn thực thi, giá trị thực sự được gán vào biến.

Hiểu lầm về var, letconst

Từ ES6, biến trong JavaScript có thể được khai báo bằng var, let hoặc const.

Hiểu lầm: Chỉ var được hoisting, còn letconst thì không.

Thực tế: Tất cả biến đều được hoisting, nhưng cách chúng hoạt động trong vùng nhớ khác nhau:

  • var: Hoisting trong global scope.
  • letconst: Hoisting trong block scope (kèm theo Temporal Dead Zone).

Ví dụ:

console.log(myName); // ReferenceError
let myName = 'JavaScript';

Đoạn mã trên báo lỗi vì biến myName nằm trong Temporal Dead Zone (TDZ) – khoảng thời gian từ khi biến được khai báo (bằng let hoặc const) đến khi nó được khởi tạo.

Hoisting với function

Hàm là một trong những khối xây dựng cơ bản của JavaScript. Có nhiều cách khai báo hàm, nhưng phổ biến nhất là:

  1. Function Declaration
  2. Function Expression
  3. Arrow Function

Function Declaration:

greetings();
function greetings() {
  console.log('Hello from dev community');
}

Đoạn mã trên không báo lỗi vì hàm được hoisting đầy đủ.

Function Expression:

greetings(); // TypeError: greetings is not a function
var greetings = function () {
  console.log('Hello from function expression');
};

Trong trường hợp này, chỉ có khai báo biến được hoisting, với giá trị mặc định là undefined.

Arrow Function:

greetings(); // TypeError: greetings is not a function
const greetings = () => {
  console.log('Hello from arrow functions');
};

Arrow function hoạt động tương tự Function Expression khi hoisting.

Thứ tự ưu tiên

Trong JavaScript, Function Declarations có độ ưu tiên cao hơn so với Variable Declarations.

Ví dụ:

var abc;
function abc() {}
console.log(typeof abc); // "function"

Kết luận

  1. Hoisting là quá trình cấp phát bộ nhớ cho các biến và hàm trước khi mã được thực thi.
  2. Chỉ có khai báo biến và hàm được hoisting.
  3. constlet được hoisting nhưng không thể truy cập trước khi khởi tạo.
  4. Function Declarations được ưu tiên hơn Variable Declarations.
  5. Để tránh lỗi hoisting, hãy luôn khai báo biến và hàm trước khi sử dụng.

Hy vọng bài viết này đã giúp bạn hiểu rõ hơn về hoisting trong JavaScript. Hãy thực hành nhiều trường hợp khác nhau để nắm vững khái niệm này nhé!

Tham khảo: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *