Javascript | "Hoisting" trong javascript
Bài đăng này đã không được cập nhật trong 4 năm
Hoisting là gì ?
Về cơ bản, khi Javascript compiles tất cả đoạn code mà bạn viết ra, tất cả các biến mà bạn khai báo bằng cách sử dụng var
sẽ tự động được đẩy lên đầu của function (nếu được khai báo bên trong một function) hoặc lên đầu của file biên dịch (nếu được khai báo bên ngoài của một function) - đó gọi là Hoisting
.
Hãy hiểu rằng, việc hoisting
(dịch ra thì đại loại là đẩy dòng code lên) không thực sự xảy ra với đoạn code mà bạn viết ra, mà việc khi trình biên dịch Javascript đọc qua đoạn mã của bạn thôi. Nên đừng bạn tâm nhiều về vấn đề đó.
Hãy hình dung là hoisting
sẽ đữa tất cả những thứ mình khai báo bằng var
lên đầu, nhưng trên lý thuyết thì không có bất cứ thứ gì được thay đổi ở đây @@.
Để có thể hiểu rõ ràng hơn về vấn đề này, mình sẽ đưa ra một vài ví dụ cơ bản để chứng minh tác động của việc hoisting.
Hãy thử với đoạn mã dưới đây trong phạm vi global scope:
console.log(myName);
var myName = ‘Ta Bich Phuong’;
Thứ gì sẽ hiện ra với console.log() kia?
Uncaught ReferenceError: myName is not defined
Ta Phuong Thao
undefined
Khi chạy file js có chứa đoạn mã kia bạn sẽ nhận ra rằng lựa chọn thứ 3 mới là câu trả lời chính xác.
Như đã nêu ở trên, các biến sẽ được di chuyển lên đầu của một scope khi trình biên dịch Javascript chạy đoạn code của bạn(ngoại trừ việc sử dụng NodeJS - ở mức rất cơ bản chỉ đơn giản là trang web của bạn đang tải). Tuy nhiên, một lưu ý quan trọng cần phải nhớ ở đây là chỉ có duy nhất các biến mới được di chuyển lên đâu thôi, chứ không phải giá trị của biến đó
.
Chỉ cần nắm rõ câu note trên là được. Có một câu hỏi khá là hay ở đây là: cho 1 file .js, tại dòng thứ 10 chúng ta khai báo: var myName = Ta Phuong Thao
thì khi file js đó được compiled đoạn khai báo biến myName sẽ ở đâu?, đoạn gán giá trị biến myName sẽ ở đâu?
Hãy đọc lại đoạn code javascript ở trên, và sau đó bạn hãy xem lại cách mà trình Javascript biên dịch ở dưới đây
var myName;
console.log(myName);
myName = ‘Ta Phuong Thao’;
Đây là lý do tại sao console.log ở trên trả về giá trị undefined
, đơn giản là biến myName đã tồn tại nhưng đơn giản là giá trị lại được khái bảo ở dòng thứ 3.
Vậy hãy thử xem ví dụ sau
function hey() {
console.log('hey ' + myName);
};
hey();
var myName = 'Ta Phuong Thao';
Function hey()
sẽ vẫn trả về giá trị undefined
, thực sự thì trình thông dịch Javascript sẽ biên dịch theo thời gian chạy:
function hey() {
console.log('hey ' + myName);
};
var myName;
hey();
myName = 'Ta Phuong Thao';
Vậy nên tại thời điểm function hey()
được gọi, nó sẽ biết rằng có một biến được gọi đến là myName
, nhưng biến này lại chưa được gán trị vào.
Vậy thì let và const thì sao?
Thực tế thì chúng cũng được hoisted, var
, let
, const
, function
và class
đều được hoisted. Điều quan trọng chúng ta cần biết là chúng không thật sự được đẩy lên đâu, chỉ có mỗi khai báo tên biến thôi, còn việc gán giá trị thì vẫn giữ nguyên vị trí.
Điểm khác biệt giữa var
, let
và const
chính là việc khai báo chúng - hiểu đơn gian là cách truyền vào giá trị cho các biến khi khai báo.
Đối với var
và let
thì có thể khai báo biến mà không cần truyền vào giá trị gì, trong khi đó const
sẽ quẳng về cho ta cái lỗi Reference error
nếu bạn có tình kháo báo một biến mà không truyền vào giá trị gì. Vậy nên đó là lý do mà const myName = 'Ta Phuong Thao'
sẽ hoạt động, còn const myName; myName='Ta Phuong Thao';
thì không.
Với var
và let
, bạn có thể sử dụng var
để khai báo và sau đó sẽ nhận được giá trị undefined
, tuy nhiên, nếu làm tương tự với let thì lại nhận được lỗi Reference Error
Vậy thì điểm khác nhau var, let và const khi hoisting là gì?
Nếu bạn tạo một biến bằng var
ở phạm vị global, thì lúc đó nó sẽ tạo ra một thuộc tình trong scope đó - ví dụ với việc bạn inspect brower, rồi khai báo var myName = 'Ta Phuong Thao';
thì có thể gọi lại biến đó thông quá window.myName (scope ở đây là window).
Tuy nhiên, nếu bạn thay thế bằng let myName = 'Ta Phuong Thao';
thì lúc này sẽ không tạo ra thuộc tính trong scope đo, dẫn đến không thế gọi thông qua window.myName.
Hoisting có ảnh hưởng như thế nào với đoạn code của bạn?
Các biến được khai báo bằng var
có thể truy cập bên ngoài scope(thông qua cách gọi property của scope đó) trong khi khai báo bằng let
và const
thì không thể.
Như chúng ta có thể thấy trong ví dụ dưới đây, khai báo bằng var
sẽ trả về giá trị undefined
trong khi đó sẽ nhận được lỗi nếu sử dụng let
và const
console.log(‘1a’, myName1); // undefined
if (1) {
console.log(‘1b’, myName1); // undefined
var myName1 = ‘Ta Phuong Thao’;
}
console.log('2a', myName2); // error: myName2 is not defined
if (1) {
console.log('2b', myName2); // undefined
let myName2 = 'Ta Phuong Thao';
}
console.log('3a', myName3); // error: myName3 is not defined
if (1) {
console.log('3b', myName3); // undefined
const myName3 = 'Ta Phuong Thao';
}
All rights reserved