Hiểu cách Hoisting hoạt động trong JavaScript

Hoisting là một cơ chế JavaScript cho phép bạn truy cập các biến và hàm trước khi bạn khởi tạo chúng. Việc lưu một khai báo như vậy sẽ chuyển nó lên đầu phạm vi của nó một cách hiệu quả.
Tìm hiểu tất cả về cách hoạt động của tính năng lưu trữ trong JavaScript và cách quản lý nó tốt nhất để tránh lỗi trong mã của bạn.
Mục Lục
Biến tồn tại với var, let và const
Có thể lưu trữ được vì JavaScript sử dụng hệ thống biên dịch JIT (Just-in-Time), hệ thống này quét mã của bạn để xác định tất cả các biến trong phạm vi tương ứng của chúng.
Sau đó, trình biên dịch JIT đưa tất cả các trường hợp khai báo biến lên đầu phạm vi của chúng khi biên dịch. JavaScript chỉ lưu trữ các khai báo của các biến chứ không lưu các phần khởi tạo của chúng.
Hành vi của các biến, khi được kéo lên, phụ thuộc vào từ khóa mà bạn khai báo chúng, vì mỗi từ khóa hoạt động khác nhau.
var
Truy cập một biến chưa khởi tạo được khai báo với var từ khóa sẽ trở lại chưa xác định. Ví dụ:
console.log(foo);
var foo = 2;
Các bản ghi mã trên chưa xác định bởi vì nó gọi console.log trước khi nó khởi tạo biến.
Trình biên dịch JavaScript xem khối mã trước đó như sau:
var foo;
console.log(foo);
foo = 2;
Trong quá trình lưu trữ, các biến tuân theo các quy tắc của phạm vi JavaScript. Javascript sẽ chỉ đưa một biến lên đầu phạm vi mà bạn đã khai báo. Việc cố gắng ghi lại giá trị của một biến bên ngoài phạm vi đã khai báo của nó sẽ dẫn đến ReferenceError. Ví dụ: nếu bạn khai báo một biến bên trong một hàm, nó sẽ không hiển thị bên ngoài phạm vi đó:
function myFunction() {
console.log(foo);
var foo = 10;
}myFunction();
console.log(foo);
Cố gắng truy cập một biến bên ngoài phạm vi của nó sẽ dẫn đến ReferenceError.
let và const
Theo tài liệu MDN trên để cho và hăng sô cẩu, JavaScript cũng lưu trữ các biến được khai báo với để cho và hăng sô từ khóa. Tuy nhiên, không giống như các biến được khai báo với var từ khóa, chúng không được khởi tạo bằng một chưa xác định giá trị.
Ví dụ:
function myFunction() {
console.log(foo);
console.log(bar);
console.log(baz); var foo = 5;
let bar = 10;
const baz = 15;
}
myFunction();
Bạn không thể truy cập các biến được khai báo với từ khóa let và const trước khi khởi tạo chúng bằng một giá trị.
Chức năng nâng
JavaScript chứa các chức năng tương tự như các biến. Đối với các biến, nó phụ thuộc vào cách bạn khai báo chúng. Ví dụ: JavaScript lưu trữ các khai báo hàm khác với các biểu thức hàm.
Khai báo hàm là một hàm được khai báo với tên, trong khi biểu thức hàm là một hàm mà bạn có thể bỏ qua tên của nó. Ví dụ:
function foo() {
}const bar = () => {
}
JavaScript chứa các khai báo hàm nhưng không lưu các biểu thức hàm. Ví dụ:
foo();
bar();
function foo() {
console.log(5);
}
var bar = function expression() {
console.log(10);
};
Mã này gọi foo trước khi khai báo và khởi tạo nó dưới dạng một hàm, nhưng nó vẫn ghi nhật ký 5 vào bảng điều khiển. Tuy nhiên, cố gắng gọi quán ba kết quả trong một TypeError.
Quản lý cẩu hàng
Nhận thức được việc lưu trữ và các lỗi tiềm ẩn có thể xảy ra nếu được quản lý sai có thể giúp bạn tiết kiệm nhiều giờ gỡ lỗi. Dưới đây là một số cách bạn có thể quản lý việc nâng hạ.
Khai báo các biến bên trong các hàm
Khai báo các biến bên trong các hàm sẽ truy cập chúng. Không phải lúc nào bạn cũng có thể làm điều này, vì bạn có thể cần một biến toàn cục mà bạn có thể truy cập trong nhiều hàm. Vì vậy, hãy đảm bảo rằng bạn chỉ khai báo các biến trên toàn cục nếu bạn thực sự cần.
Khai báo các biến với let hoặc const
Bạn nên luôn sử dụng let và Const từ khóa thay cho var từ khóa khi khai báo biến. Thực hành này có lợi khi khai báo các biến cục bộ bên trong một hàm. Biết các cách thích hợp để khai báo các biến trong JavaScript giúp giảm nguy cơ xảy ra lỗi do quá trình lưu trữ xảy ra trong mã của bạn.
Khai báo các biến ở đầu phạm vi của chúng
Khai báo tất cả các biến của bạn ở đầu phạm vi tương ứng của chúng, trước bất kỳ câu lệnh nào khác. Làm như vậy sẽ đảm bảo trình biên dịch JavaScript không phải kéo các biến đó lên để truy cập chúng.
Sử dụng Chế độ nghiêm ngặt
Chế độ nghiêm ngặt là một chế độ JavaScript điều chỉnh cú pháp kém, tối ưu hóa thời gian chạy mã của bạn và cấm lạm dụng cú pháp được đánh máy lỏng lẻo của JavaScript bằng cách tạo ra lỗi trong thời gian biên dịch.
Ví dụ: trong “chế độ cẩu thả”, do quá trình treo, bạn có thể truy cập vào một biến bên ngoài hàm đã khởi tạo, ngay cả khi nó không được khai báo:
myFunction();
console.log(foo); function myFunction() {
foo = 20;
}
Trong khối mã ở trên, JavaScript tự động khai báo foo và nâng nó lên đầu phạm vi toàn cầu, bỏ qua phạm vi bạn đã khởi tạo nó.
Bạn có thể sử dụng chế độ nghiêm ngặt để khắc phục hành vi này và thông báo lỗi nếu bạn cố gắng truy cập biến bên ngoài phạm vi chức năng của nó.
Chế độ nghiêm ngặt không ngừng nâng hoàn toàn. Thay vào đó, nó ngăn chặn các hình thức cẩu thả khó hiểu và dễ xảy ra lỗi nhất. Điều quan trọng vẫn là hiểu khái niệm chung và các quy tắc đằng sau vận thăng, ngay cả khi sử dụng mạng an toàn chế độ nghiêm ngặt.
Để chọn tham gia chế độ nghiêm ngặt ở cấp độ toàn cầu, hãy khai báo cú pháp ở đầu tệp tập lệnh của bạn:
"use strict"; // or 'use strict'
Để chọn tham gia chế độ nghiêm ngặt ở cấp hàm, hãy khai báo cú pháp ở đầu thân hàm trước bất kỳ câu lệnh nào:
function myStrictFunction() {
"use strict";
}
Nếu bạn khai báo chế độ nghiêm ngặt ở một cấp hàm, cài đặt sẽ chỉ áp dụng cho các câu lệnh bên trong hàm đó.
Khai báo chế độ nghiêm ngặt ở cấp độ toàn cầu ngăn các biến được truy cập bên ngoài phạm vi tương ứng của chúng:
"use strict";
myFunction();
console.log(foo); function myFunction() {
foo = 20;
}
Khi bật chế độ nghiêm ngặt, trình biên dịch JavaScript sẽ lưu trữ myFunction () lên đầu phạm vi của nó mà không có biến chưa khai báo.
Hiểu điều gì ảnh hưởng đến việc nâng hạ
Hoisting khá độc đáo đối với JavaScript và có thể là một hành vi rất khó hiểu đối với bạn. Nó có thể ảnh hưởng đến các biến và hàm, nhưng có những cách để ngăn chặn nếu bạn cần.
Một số yếu tố có thể ảnh hưởng đến quá trình lưu trữ, vì vậy tốt nhất là tránh bất kỳ sự xuất hiện của biến hoặc chức năng nào trong mã của bạn.