Skip to content

Lesson 1.1.2 — Global Execution Context ​

Bài 1.1.2 — Global Execution Context
Global Code, Global Environment & Top-level Execution • 21 phút
0:00 / 0:00

0. Metadata (Thông tin bài học) ​

TrườngGiá trị
Stage1 — JavaScript Execution Model
Module1.1 — Execution Context
Lesson1.1.2 — Global Execution Context
CompetencyC02 — JavaScript Runtime
DepthL2–L3 (Explain → Use)
PrerequisitesLesson 1.1.1 — Execution Context là gì?
Thời gian ước tính30–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:

js
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 = 1 lại tạo ra window.x trong Browser
  • Không hiểu tại sao function foo() {} ở global lại có thể gọi qua window.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.log và gọi hàm

3. Learning Objectives (Mục tiêu học tập) ​

Sau bài này, bạn có thể:

  1. Giải thích Global Execution Context được tạo ra khi nào và chứa những gì
  2. Phân biệt sự khác nhau giữa Browser global object (window) và Node.js global object (global) ở mức conceptual
  3. Dự đoán biến nào trở thành property của global object và biến nào không
  4. 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 (window trong Browser, global trong 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. var và function declaration ở top-level giống như để đồ ra sảnh chung (window). Còn let/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 qua window được.

text
┌─────────────────────────────────────────┐
│     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)
  • this binding (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:

js
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ên window

Bước 3 — Lý luận từng bước

text
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:

js
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:

  1. Dòng nào in ra undefined? Dòng nào in ra giá trị thực?
  2. Tại sao let/const lại khác var ở điểm này?
  3. Nếu đoạn code này chạy trong Node.js, window có tồn tại không?
[Đáp án & Giải thích]
  • Bạn nghĩ

    1. window.a → 1, window.test → function. window.b và window.c → undefined.
    2. Vì let/const tạo binding trong lexical environment, không tạo property trên global object.
    3. Không, Node.js không có window. Thay vào đó là global hoặc globalThis.
  • Giải thích

    • var a và function test tạo property trên global object → truy cập qua window được
    • let b và const c chỉ tạo binding trong Global Execution Context, không "leak" lên window
    • Trong Node.js REPL hoặc script, window là undefined. Dùng globalThis để 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ả:

js
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):

js
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ỉ var và 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ào window.

9. Edge Cases (Các trường hợp ngoại lệ) ​

Case 1 — let/const trùng tên với window property ​

js
let name = "app";
console.log(window.name);
  • What fails? window.name không phải "app". Trong Browser, window.name là built-in property (tên của window) và let ở global không ghi đè nó.
  • Why? let/const khô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ên window.
  • How to observe? console.log(name) → "app" (biến let vẫn tồn tại trong global scope), nhưng console.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ến let/const, dùng trực tiếp identifier thay vì window.x.

Case 2 — Global object trong Node.js ​

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.setTimeout sẽ crash trong Node.js. Dùng globalThis.setTimeout để chạy được ở cả hai môi trường.
  • Production connection: Library cross-platform (như lodash, axios) luôn dùng globalThis thay 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):

js
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ằng let/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 window properties
  • Dùng const cho 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 ý

  1. IIFE (Immediately Invoked Function Expression): Bọc mỗi thư viện trong (function() { ... })() để tạo Function Execution Context riêng, biến var bên trong không leak ra global.
  2. Chuyển var thành let/const: Nếu browser hỗ trợ ES6, dùng let/const ở top-level để không tạo property trên window, tránh ghi đè lẫn nhau.

13. AI-Assisted Exercise (Bài tập với AI) ​

Level A — Ask

  1. Tự trả lời trước: Viết ra giấy: "Global Execution Context chứa những gì? var và let khác nhau thế nào ở global level?"
  2. 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?"
  3. So sánh: AI có nhắc đến globalThis không? AI có giải thích tại sao let không tạo property trên window không, hay chỉ nói "let is block-scoped"?
  4. 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). var tạo property trên global object, let/const chỉ 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: var tạo property trên global object, let thì 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, let vẫ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.
  • Điểm AI nói sai hoặc quá mơ hồ

    • AI nói let là "block-scoped" ở global level. Kỹ thuật đúng, nhưng ở global scope (không nằm trong hàm hay block nào), let vẫ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ùng window sẽ crash trong Node.js.
  • 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ờ, var và function declaration khi khai báo ở top-level sẽ tự động tạo property trên window. Nên var x = 1 nghĩa là window.x = 1. Nhưng let và const thì khác — chúng vẫn nằm trong global scope, vẫn global binding, nhưng không tạo property trên window. Vì vậy window.y là undefined, dù y vẫ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ùng let/const thay 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à: var là để đồ ra sảnh chung (global object) — ai cũng thấy. let/const là để đồ 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 qua window được.

Gợi ý đánh giá bản thân

  • Đồng nghiệp có hiểu tại sao window.y undefined không? Hay họ vẫn nghĩ let không phải global?
  • Bạn có dự đoán được câu hỏi tiếp theo: "Vậy let có 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 objectCompare (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 propertyPrediction (Dự đoán)Cho 4 khai báo global, đoán cái nào thành window.x
Nhận diện global pollutionDebug (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/function leak lên global object còn let/const thì 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 var và function lạ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)
📴 Offline Mode — Content served from cache