Nguyên lý thực thi mã lệnh trong JavaScript dựa trên một số khái niệm cơ bản về cách mà mã JavaScript được xử lý và thực thi trong trình duyệt web hoặc môi trường Node.js. Dưới đây là các nguyên lý chính liên quan đến thực thi mã lệnh trong JavaScript:
1. Nhúng JavaScript Vào HTML
Inline Script: Mã JavaScript có thể được nhúng trực tiếp vào các thẻ <script> trong tài liệu HTML.
<script>
console.log("Hello, World!");
</script>
External Script: Mã JavaScript cũng có thể được đưa vào các tập tin .js riêng biệt và liên kết với tài liệu HTML thông qua thuộc tính src của thẻ <script>.
<script src="script.js"></script>
2. Thực Thi Theo Thứ Tự
3. Khái Niệm Vòng Lặp Event Loop
Event Loop: JavaScript là ngôn ngữ đồng bộ đơn luồng, nhưng nó sử dụng event loop để xử lý các tác vụ không đồng bộ (như I/O, hẹn giờ). Event loop cho phép JavaScript thực thi các nhiệm vụ không đồng bộ mà không chặn luồng chính.
Call Stack: Nơi thực thi các hàm được gọi. Khi một hàm được gọi, nó được đưa vào call stack và khi hàm kết thúc, nó được loại bỏ khỏi call stack.
Task Queue (Message Queue): Nơi lưu trữ các tác vụ không đồng bộ như các sự kiện và các callback từ các hàm setTimeout, setInterval, hoặc các yêu cầu mạng.
Event Loop: Kiểm tra call stack và task queue. Khi call stack trống, event loop sẽ chuyển các tác vụ từ task queue vào call stack để thực thi.
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
console.log("End");
Kết quả sẽ là:
Start
End
Timeout
4. Thực Thi Đồng Bộ và Không Đồng Bộ
Đồng Bộ: Các câu lệnh được thực thi một cách tuần tự, từng cái một. Nếu một câu lệnh tốn thời gian (như một vòng lặp lớn), nó sẽ chặn thực thi của các câu lệnh khác.
Không Đồng Bộ: JavaScript hỗ trợ các thao tác không đồng bộ thông qua các API như setTimeout, setInterval, và các Promise. Các tác vụ không đồng bộ sẽ được đưa vào task queue và sẽ được thực thi sau khi call stack trống.
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 1000);
console.log("End");
Kết quả sẽ là:
Start
End
Timeout
5. Scope (Phạm Vi Biến)
Global Scope: Các biến và hàm khai báo bên ngoài mọi hàm và khối lệnh thuộc phạm vi toàn cục (global scope).
Local Scope: Các biến và hàm khai báo trong một hàm hoặc khối lệnh chỉ có hiệu lực trong phạm vi đó (local scope).
Block Scope: Với ES6, let và const tạo ra phạm vi khối (block scope), tức là các biến khai báo với let và const chỉ có thể được truy cập trong khối {} mà chúng được khai báo.
function testScope() {
var x = 1; // local scope
if (true) {
let y = 2; // block scope
console.log(x); // 1
console.log(y); // 2
}
console.log(x); // 1
console.log(y); // ReferenceError: y is not defined
}
6. Hoisting (Nâng Cao)
Hoisting: JavaScript hoisting là cơ chế trong đó các khai báo biến và hàm được nâng lên đầu phạm vi của chúng trước khi thực thi mã. Điều này có nghĩa là bạn có thể gọi một hàm hoặc sử dụng một biến trước khi chúng được khai báo.
console.log(a); // undefined
var a = 5;
greet(); // "Hello"
function greet() {
console.log("Hello");
}
7. Execution Context (Ngữ Cảnh Thực Thi)
Global Execution Context: Ngữ cảnh thực thi toàn cục, nơi toàn bộ mã JavaScript được thực thi lần đầu tiên.
Function Execution Context: Khi một hàm được gọi, một ngữ cảnh thực thi mới được tạo ra cho hàm đó.
Creation Phase: Trong giai đoạn tạo ngữ cảnh thực thi, các khai báo biến và hàm được thực hiện.
Execution Phase: Trong giai đoạn thực thi, mã trong ngữ cảnh thực thi được thực thi theo thứ tự.
function foo() {
console.log(x); // undefined
var x = 10;
console.log(x); // 10
}
foo();
8. Memory Management (Quản Lý Bộ Nhớ)
- Garbage Collection: JavaScript tự động quản lý bộ nhớ thông qua garbage collection, giúp giải phóng bộ nhớ không còn sử dụng. Garbage collector sẽ tìm và xóa các đối tượng không còn tham chiếu đến.
Tóm Tắt:
- JavaScript thực thi mã nguồn theo thứ tự từ trên xuống dưới.
- Event loop và task queue giúp xử lý các tác vụ không đồng bộ.
- Scope và hoisting ảnh hưởng đến cách các biến và hàm được xử lý.
- Execution context bao gồm các giai đoạn tạo và thực thi mã.
Hiểu rõ những nguyên lý này giúp bạn viết mã hiệu quả và dễ dàng hơn trong việc gỡ lỗi và tối ưu hóa ứng dụng JavaScript.