Sau khi nắm được nó chúng ta có thể giải thích những vấn đề cao siêu như hoisting, scope chain, closure.
Để hiểu Execution Context, ngẫm lại cách chúng ta viết code: chúng ta tách nó ra thành những phần nhỏ riêng biệt. Những “phần nhỏ” này có các tên gọi như function, module, package, tất cả là để chia nhỏ, dễ quản lý một mớ code vừa to vừa phức tạp.
Nếu Javascript là một người thực thi các đoạn code này, nó cũng dùng cách tương tự, thực thi từng phần code một, được gọi là Execution Context
Có 2 loại Execution Context:
- Global Execution Context
- Function Execution Context
Global Execution Context
Được tạo khi javascript chạy code của chúng ta, bình thường nó sẽ tạo ra 2 thứ: 1 global object và một biến gọi là this
. this
sẽ trỏ tới global object là window nếu chạy trên trình duyệt, trỏ tới global
nếu chạy trên Node
Khi chúng ta khai báo thêm biến
Creation phase của Global Execution context sẽ có các bước
- Tạo global object
- Tạo object tên là
this
- Setup vùng nhớ tạm thời cho biến và function
- Gắn giá trị
undefined
cho biến, trỏ từng function đến vùng nhớ.
Thử log giá trị sau creation phase và trước execution phase
Trước khi javascript thực sự chạy các dòng code, creation phase xảy ra trước, nên giá trị log ra sẽ là undefined
, function sẽ trỏ tới một vùng nhớ.
console.log('name: ', name) // name: undefined
console.log('handle: ', handle) // handle: undefined
console.log('getUser :', getUser) // getUser: ƒ getUser () {}
var name = 'Tyler'
var handle = '@tylermcginnis'
function getUser () {
return {
name: name,
handle: handle
}
}
Function Execution Context
Được tạo ra khi thực thi hàm, cơ bản nó cũng giống với Global execution context, khác ở chỗ nó bỏ bước #1
Tạo global object- Tạo một object tên
arguments
- Tạo object tên là
this
- Setup vùng nhớ tạm thời cho biến và function
- Gắn giá trị
undefined
cho biến, trỏ từng function đến vùng nhớ.
Bạn có thấy cái ô màu hồng hồng trên hình nó xuất hiện khi function được thực thi, sau đó bị remove sau khi chạy xong. Khi tạo một execution context, javascript đưa vào một hàng đợi gọi là Call Stack, sau khi đã chạy xong 2 phase nó remove khỏi Call Stack
Với một function có khai báo biến bên trong
Quá hiển nhiên là biến handle
nằm trong Global Execution Context, nên bên trong function chúng ta có thể access đến nó, trong khi biến twitterURL
được khởi tạo ở trong function, nó chỉ có trong Function Execution Context khi hàm được thực thi. Đây chính là nền tảng của khái niệm SCOPE
Chúng ta đã biết scope ám chỉ việc biến có thể truy xuất ở đâu. Trên MDN nó định nghĩa scope
Scope: The current context of execution.
Giờ bạn nghĩ xem, cái gì sẽ được log ra sau khi chạy hàm
function first () {
var name = 'Jordyn'
console.log(name)
}
function second () {
var name = 'Jake'
console.log(name)
}
console.log(name)
var name = 'Tyler'
first()
second()
console.log(name)
Chúng ta sẽ có thứ tự log ra: undefined
, Jordyn
, Jake
, Tyler
Trong trường hợp biến không tồn tại trong execution context của function, liệu nó sẽ log ra cái gì, hay ngừng chạy?
var name = 'Tyler'
function logName () {
console.log(name)
}
logName()
Kết quả log ra là "Tyler", dù bên trong execution context của hàm không có biến, nó sẽ tìm đến thằng context cha xem có giá trị của biến này chưa, cho đến khi global execution context nó sẽ dừng.
Tham khảo thêm
Mình đã viết bài này trên MDN Closures
The Ultimate Guide to Execution Contexts, Hoisting, Scopes, and Closures in JavaScript
Initializing...