Lesson 1.1.2 — Global Execution Context
0. Metadata (Thông tin bài học)
| Trường | Giá trị |
|---|---|
| Stage | 1 — JavaScript Execution Model |
| Module | 1.1 — Execution Context |
| Lesson | 1.1.2 — Global Execution Context |
| Competency | C02 — JavaScript Runtime |
| Depth | L2–L3 (Explain → Use) |
| Prerequisites | Lesson 1.1.1 — Execution Context là gì? |
| Thời gian ước tính | 30–40 phút |
1. Why This Exists (Vì sao cần học)
Ở bài trước, bạn đã biết Execution Context là container nơi code chạy. Bạn cũng biết có hai loại chính: Global và Function.
Nhưng câu hỏi quan trọng hơn là:
Khi bạn mở file JavaScript, điều gì xảy ra trước dòng code đầu tiên?
Nếu bạn viết:
const app = "JEM";
function init() {
console.log("ready");
}
init();Engine không bắt đầu bằng cách chạy const app = "JEM". Trước đó, nó đã tạo ra một container đặc biệt — Global Execution Context — và chuẩn bị sẵn một số thứ bên trong.
Nếu không hiểu Global Execution Context, bạn sẽ:
- Không hiểu tại sao
var x = 1lại tạo rawindow.xtrong Browser - Không hiểu tại sao
function foo() {}ở global lại có thể gọi quawindow.foo() - Không nhận ra nguy cơ global pollution khi khai báo quá nhiều biến ở top-level
- Không phân biệt được code chạy trong Browser và Node.js ở mức cơ bản
Bài này đi sâu vào container đầu tiên đó.
2. Prerequisites (Yêu cầu đầu vào)
Bạn cần đã học:
- Lesson 1.1.1 — Execution Context là gì?
- Biết phân biệt
const/let/varở mức cơ bản (Stage 0) - Biết
console.logvà gọi hàm
3. Learning Objectives (Mục tiêu học tập)
Sau bài này, bạn có thể:
- Giải thích Global Execution Context được tạo ra khi nào và chứa những gì
- Phân biệt sự khác nhau giữa Browser global object (
window) và Node.js global object (global) ở mức conceptual - Dự đoán biến nào trở thành property của global object và biến nào không
- Nhận diện global pollution trong một đoạn code thực tế
4. Mental Model (Mô hình tư duy)
Global Execution Context = Container gốc
Khi engine bắt đầu chạy một script, nó tạo ra một và chỉ một Global Execution Context cho script đó. Context này:
- Luôn tồn tại từ đầu đến khi script kết thúc
- Chứa mọi biến và hàm được khai báo ở "top-level" (không nằm trong hàm nào)
- Liên kết với một global object (
windowtrong Browser,globaltrong Node.js) - Cung cấp "điểm truy cập cuối cùng" khi engine không tìm thấy biến ở các context bên trong
💡 Hình dung như tòa nhà khách sạn: Global Context là sảnh chung (lobby) — ai cũng vào được, đồ để ở đây ai cũng thấy.
varvàfunction declarationở top-level giống như để đồ ra sảnh chung (window). Cònlet/constở top-level giống như để đồ trong phòng riêng của bạn — bạn vẫn dùng được, nhưng không ai lấy quawindowđược.
┌─────────────────────────────────────────┐
│ Global Execution Context │
│ ┌─────────────────────────────────┐ │
│ │ Global Object │ │
│ │ • window (Browser) │ │
│ │ • global (Node.js) │ │
│ │ • globalThis (universal) │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Global Bindings │ │
│ │ • const app = "JEM" │ │
│ │ • function init() {...} │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘var ≠ let/const ở global level
Đây là điểm gây confusion nhất: var tạo property trên global object, nhưng let/const thì không. Cả hai đều "global" về mặt scope, nhưng chỉ var và function declaration mới "dính" vào window.
5. Core Concepts (Các khái niệm cốt lõi)
Essential (Bắt buộc)
- Global Execution Context (GEC): Context mặc định, tạo ra ngay khi script bắt đầu, tồn tại cho đến khi script kết thúc
- Global Object: Object gốc mà GEC liên kết đến. Chứa built-in API (
console,setTimeout, v.v.) - Global Bindings: Các biến và hàm khai báo ở top-level
- Global Pollution: Hiện tượng khai báo quá nhiều biến ở global scope, gây xung đột tên
Supporting (Hỗ trợ)
globalThis: Cách truy cập global object đồng nhất giữa Browser và Node.js- Sự khác biệt cơ bản giữa Browser (có DOM) và Node.js (không có DOM)
Awareness (Biết tồn tại)
eval()tạo Eval Execution Context (không nên dùng)- Module scope (ESM) không phải global scope, nhưng chưa học ở bài này
Out of Scope (Không học trong bài này)
- Creation Phase chi tiết (bài 1.1.4)
- Hoisting mechanism (Module 1.3)
thisbinding (Stage 2)- ESM vs CJS module system (Stage 7)
6. Worked Example (Ví dụ phân tích từng bước)
Xem đoạn code sau chạy trong Browser:
var version = "1.0";
function start() {
console.log("starting");
}
const author = "team";
console.log(window.version);
console.log(window.start);
console.log(window.author);Bước 1 — Quan sát Có 3 khai báo top-level: var version, function start, const author.
Bước 2 — Phân loại
var version→ tạo property trên global object (window.version)function start→ tạo property trên global object (window.start)const author→ tạo binding trong GEC, không tạo property trênwindow
Bước 3 — Lý luận từng bước
1. Engine tạo Global Execution Context
→ Global Object (window) được khởi tạo
2. Engine xử lý khai báo top-level
→ window.version = "1.0" (vì dùng var)
→ window.start = function (vì là function declaration)
→ author = "team" (binding trong GEC, không trên window)
3. Dòng 7: console.log(window.version)
→ Truy cập window.version → "1.0"
4. Dòng 8: console.log(window.start)
→ Truy cập window.start → function object
5. Dòng 9: console.log(window.author)
→ Truy cập window.author → undefined (không tồn tại trên window)Bước 4 — Kết luậnvar và function declaration ở global level "leak" lên global object. let/const thì không. Đây là lý do let/const được khuyến khích hơn var ở top-level.
7. Prediction Exercise (Bài tập dự đoán)
Đừng chạy code. Đọc và trả lời:
var a = 1;
let b = 2;
const c = 3;
function test() {
console.log("test");
}
console.log(window.a);
console.log(window.b);
console.log(window.c);
console.log(window.test);Câu hỏi:
- Dòng nào in ra
undefined? Dòng nào in ra giá trị thực? - Tại sao
let/constlại khácvarở điểm này? - Nếu đoạn code này chạy trong Node.js,
windowcó tồn tại không?
[Đáp án & Giải thích]
Bạn nghĩ
window.a→1,window.test→ function.window.bvàwindow.c→undefined.- Vì
let/consttạo binding trong lexical environment, không tạo property trên global object. - Không, Node.js không có
window. Thay vào đó làglobalhoặcglobalThis.
Giải thích
var avàfunction testtạo property trên global object → truy cập quawindowđượclet bvàconst cchỉ tạo binding trong Global Execution Context, không "leak" lênwindow- Trong Node.js REPL hoặc script,
windowlàundefined. DùngglobalThisđể viết code chạy được ở cả hai môi trường.
8. Implementation Lab (Bài lab thực hành)
Lab 1 — Kiểm tra Global Object (Guided)
Mở DevTools Console trong Browser và chạy từng dòng sau. Ghi lại kết quả:
var x = 10;
let y = 20;
const z = 30;
console.log(window.x);
console.log(window.y);
console.log(window.z);
console.log("x" in window);
console.log("y" in window);Gợi ý
Dòng nào trả về true? Dòng nào trả về false? Kết quả này chứng minh điều gì về sự khác biệt giữa var và let/const?
Lab 2 — Global Pollution Detector (Independent)
Cho đoạn code sau. Hãy liệt kê tất cả các tên có thể gây global pollution (tức là trở thành property của global object):
var appName = "MyApp";
var appVersion = "2.0";
function initApp() {
const config = { debug: true };
console.log("init");
}
function render() {
console.log("render");
}
let userCount = 0;
const MAX_USERS = 100;[Đáp án tham khảo]
Danh sách gây global pollution
appName(var)appVersion(var)initApp(function declaration)render(function declaration)
Không gây global pollution
config(const, nằm trong function)userCount(let, top-level nhưng không tạo property trên window)MAX_USERS(const, tương tự)
Giải thích Chỉ
varvàfunction declarationở top-level mới tạo property trên global object.let/constở top-level vẫn là global scope nhưng không "dính" vàowindow.
9. Edge Cases (Các trường hợp ngoại lệ)
Case 1 — let/const trùng tên với window property
let name = "app";
console.log(window.name);- What fails?
window.namekhông phải"app". Trong Browser,window.namelà built-in property (tên của window) vàletở global không ghi đè nó. - Why?
let/constkhông tạo property trên global object. Nếu global object đã có property sẵn (nhưname), hai thứ tồn tại song song: binding trong GEC và property trênwindow. - How to observe?
console.log(name)→"app"(biếnletvẫn tồn tại trong global scope), nhưngconsole.log(window.name)→""(giá trị mặc định của DOM property, hoàn toàn độc lập) - How to fix/decide? Tránh đặt tên biến global trùng với built-in property của
window(name,status,length, v.v.). Nếu cần kiểm tra biếnlet/const, dùng trực tiếp identifier thay vìwindow.x.
Case 2 — Global object trong Node.js
// Node.js environment
console.log(window); // ReferenceError: window is not defined
console.log(global); // [object global]
console.log(globalThis); // [object global]- What happens? Node.js không định nghĩa
window. Global object làglobal. - Why it matters? Code dùng
window.setTimeoutsẽ crash trong Node.js. DùngglobalThis.setTimeoutđể chạy được ở cả hai môi trường. - Production connection: Library cross-platform (như lodash, axios) luôn dùng
globalThisthay vìwindow.
10. Debug Lab (Bài lab gỡ lỗi)
Symptom (Triệu chứng): Developer báo cáo: "Tôi khai báo let name = "App" ở đầu file, nhưng khi log window.name ra lại là chuỗi rỗng."
Reproduction (Tái hiện lỗi):
let name = "App";
console.log(name); // "App"
console.log(window.name); // ""Evidence (Bằng chứng): name in ra đúng, nhưng window.name không giống.
Hypothesis (Giả thuyết): let ở global level không tạo property trên global object. window.name là built-in property của Browser và hoàn toàn độc lập với biến name được khai báo bằng let.
Verification (Xác minh): Thử đổi let thành var name = "App" — lúc này window.name trả về "App" vì var tạo property trên global object.
Root Cause (Nguyên nhân gốc rễ): Nhầm lẫn giữa global scope binding (let/const) và global object property (var/function). Trong Browser, window.name là DOM property có sẵn, không liên quan đến JavaScript lexical binding.
Prevention (Phòng ngừa):
- Không dùng
window.xđể kiểm tra biến được khai báo bằnglet/const. Nếu cần kiểm tra biến global, dùng trực tiếp identifier (name) thay vìwindow.name— điều này phòng ngừa nhầm lẫn giữa binding và property. - Không đặt tên biến global trùng với built-in
windowproperties - Dùng
constcho mọi giá trị không đổi ở top-level để giảm global pollution
11. Design Exercise (Bài tập thiết kế giải pháp)
Không áp dụng ở Depth L2–L3.
12. Production Scenario (Tình huống thực tế)
Context: Một ứng dụng legacy sử dụng nhiều thư viện JavaScript được nối qua thẻ <script>. Mỗi thư viện đều dùng var ở top-level.
Constraint: Không thể refactor toàn bộ sang module system ngay lập tức.
Symptom: Thư viện A khai báo var config = { api: "v1" }. Thư viện B cũng khai báo var config = { theme: "dark" }. Khi load xong, ứng dụng gọi API sai endpoint vì config bị ghi đè.
Decision cần đưa ra: Dùng kiến thức về Global Execution Context, bạn sẽ đề xuất 2 giải pháp khả thi để ngăn xung đột mà không cần rewrite toàn bộ codebase.
Gợi ý
- IIFE (Immediately Invoked Function Expression): Bọc mỗi thư viện trong
(function() { ... })()để tạo Function Execution Context riêng, biếnvarbên trong không leak ra global. - Chuyển
varthànhlet/const: Nếu browser hỗ trợ ES6, dùnglet/constở top-level để không tạo property trênwindow, tránh ghi đè lẫn nhau.
13. AI-Assisted Exercise (Bài tập với AI)
Level A — Ask
- Tự trả lời trước: Viết ra giấy: "Global Execution Context chứa những gì?
varvàletkhác nhau thế nào ở global level?" - Hỏi AI: Dùng prompt: "What is the difference between var and let at the global scope in JavaScript? Does let create a property on the window object?"
- So sánh: AI có nhắc đến
globalThiskhông? AI có giải thích tại saoletkhông tạo property trênwindowkhông, hay chỉ nói "let is block-scoped"? - Verify: Mở MDN trang "var" và "let", kiểm chứng phần "global object property" behavior.
Gợi ý
Để ý xem AI có trả lời mơ hồ kiểu "let is better because it's block-scoped" không. Câu trả lời đúng cần chỉ ra: var tạo property trên global object, let/const thì không — dù cả hai đều ở global scope. Nếu AI không phân biệt được "global scope" và "global object property", bạn đã tìm ra điểm mù.
Đáp án tham khảo
Bạn nghĩ Global Execution Context chứa global object (window/global), global bindings (biến và hàm top-level), và outer reference (null vì đây là context gốc).
vartạo property trên global object,let/constchỉ tạo binding trong GEC.AI trả lời
- "Both var and let declare variables, but var is function-scoped while let is block-scoped."
- "At the global level, var declarations create a property on the global object, while let declarations do not."
- "This means you can access var variables via window.variableName in browsers, but not let variables."
- "let was introduced in ES6 to solve some of the problems with var."
So sánh
- AI đúng về điểm chính:
vartạo property trên global object,letthì không. - AI dùng "block-scoped" để giải thích
letở global level — điều này kỹ thuật là đúng nhưng dễ gây hiểu nhầm. Ở global level,letvẫn nằm trong global scope, không phải "block scope" theo nghĩa{ }. - AI không nhắc đến
globalThis— một điểm mù quan trọng nếu bạn cần viết code cross-platform.
- AI đúng về điểm chính:
Điểm AI nói sai hoặc quá mơ hồ
- AI nói
letlà "block-scoped" ở global level. Kỹ thuật đúng, nhưng ở global scope (không nằm trong hàm hay block nào),letvẫn tạo binding ở global lexical environment — không phải "block" theo nghĩa thông thường. Điều này có thể khiến learner nghĩletở global không phải global scope. - AI không đề cập đến sự khác biệt giữa Browser (
window) và Node.js (global). Nếu bạn chỉ dựa vào AI, bạn sẽ không biết code dùngwindowsẽ crash trong Node.js.
- AI nói
Kết luận Nếu bạn phát hiện AI thiếu context về cross-environment (Browser vs Node.js) và dùng từ "block-scoped" một cách mơ hồ, bạn đã hiểu sâu hơn AI về Global Execution Context. Điều này sẽ cực kỳ quan trọng khi bạn học Module 1.5 (Call Stack) và Stage 7 (Module System), nơi environment khác nhau sẽ tạo ra global context khác nhau.
14. Teach Back (Dạy lại)
Yêu cầu: Giả sử một junior developer hỏi: "Tôi thấy var x = 1 và let y = 2 đều khai báo ở đầu file. Tại sao window.x thì được mà window.y lại undefined?" Hãy giải thích trong 2 phút, dùng khái niệm Global Execution Context và global object.
Mô phỏng
- Bạn nói Khi file JavaScript chạy, engine tạo ra Global Execution Context — cái hộp lớn nhất chứa toàn bộ code top-level. Bên trong hộp này có một global object, trong Browser là
window. Bây giờ,varvàfunction declarationkhi khai báo ở top-level sẽ tự động tạo property trênwindow. Nênvar x = 1nghĩa làwindow.x = 1. Nhưngletvàconstthì khác — chúng vẫn nằm trong global scope, vẫn global binding, nhưng không tạo property trênwindow. Vì vậywindow.ylà undefined, dùyvẫn tồn tại và dùng được trong file. Đây chính xác là lý do người ta khuyên dùnglet/constthay vìvarở top-level: để tránh "leak" biến ra global object và gây xung đột với thư viện khác.
💡 Hình dung như thuê nhà:
varlà để đồ ra sảnh chung (global object) — ai cũng thấy.let/constlà để đồ trong phòng riêng của bạn (global binding) — bạn vẫn dùng được, nhưng không ai lấy quawindowđược.
Gợi ý đánh giá bản thân
- Đồng nghiệp có hiểu tại sao
window.yundefined không? Hay họ vẫn nghĩletkhông phải global? - Bạn có dự đoán được câu hỏi tiếp theo: "Vậy
letcó phải global không?" không? (Câu trả lời: Có, về scope, nhưng không phải property của global object.) - Bạn có thể liên tưởng đến Node.js được không? (Ở Node.js không có
window, chỉ cóglobal.)
15. Assessment (Đánh giá)
| Objective (Mục tiêu) | Hình thức đánh giá | Nội dung |
|---|---|---|
| Giải thích GEC chứa gì | Explain (Giải thích) | Liệt kê 3 thành phần chính của GEC |
| Phân biệt Browser/Node.js global object | Compare (So sánh) | Cho 2 snippet sử dụng window vs globalThis, xác định cái nào chạy được ở Browser, cái nào ở Node.js |
| Dự đoán global object property | Prediction (Dự đoán) | Cho 4 khai báo global, đoán cái nào thành window.x |
| Nhận diện global pollution | Debug (Phân tích) | Cho file 30 dòng, đếm số biến leak ra global object |
16. Exit Criteria (Tiêu chí qua bài)
- [ ] Có thể giải thích Global Execution Context được tạo ra khi nào và tồn tại trong bao lâu
- [ ] Có thể liệt kê ít nhất 3 thứ chứa bên trong GEC (global object, global bindings, outer reference)
- [ ] Có thể dự đoán đúng biến nào trở thành property của global object trong 3/4 trường hợp (
var,let,const,function) - [ ] Có thể phân biệt
window(Browser) vàglobal(Node.js) ở mức conceptual - [ ] Có thể nhận diện global pollution trong một file có nhiều khai báo top-level
17. Spiral Connection (Liên kết xoắn ốc)
Previous (Trước): Lesson 1.1.1 — Bạn đã biết Execution Context là container chạy code. Bạn biết có Global Context và Function Context.
Current (Hiện tại): Bạn hiểu Global Execution Context là container gốc, luôn tồn tại, chứa global object và global bindings. Bạn biết
var/functionleak lên global object cònlet/constthì không.Next (Tiếp theo):
- 1.1.3 — Function Execution Context (container tạo ra mỗi khi gọi hàm)
- 1.2.x — Scope & Lexical Environment (biến tìm nhau giữa các context như thế nào)
- 1.3.x — Hoisting (tại sao
varvàfunctionlại "xuất hiện" trước khi code chạy)- S7 — Module System (ESM tạo module scope, không phải global scope)
- S11 — Memory (global object giữ reference → nguy cơ memory leak)