Skip to content

Lesson 0.1.1 — JavaScript là gì? ​

Bài 0.1.1 — JavaScript là gì?
ECMAScript, Engine, Runtime & Host Environment • 18 phút
0:00 / 0:00

0. Metadata ​

Thuộc tínhGiá trị
Stage0
Module0.1 — JavaScript & Runtime Fundamentals
Lesson0.1.1
CompetencyC01 — JavaScript Language
DepthL2–L3 (Explain → Use)
PrerequisitesKhông
Cognitive LoadThấp–Trung bình

1. Why This Exists (Vì sao cần học) ​

Bạn viết một đoạn JavaScript đơn giản:

js
console.log(typeof document);

Chạy trong Browser, kết quả là "object".
Chạy trong Node.js, kết quả là "undefined".

Cùng một ngôn ngữ. Cùng một câu lệnh. Kết quả khác nhau.

Hiểu nhầm phổ biến

Nếu bạn nghĩ "JavaScript là một ngôn ngữ và nó chạy như nhau ở mọi nơi", bạn đang thiếu một mental model quan trọng. Đây là nguyên nhân gốc rễ của hàng loạt bug production — đặc biệt là khi code được share giữa client và server (SSR).

Bài học này tồn tại để bạn hiểu:

JavaScript không chạy trong chân không. Nó chạy trong một hệ sinh thái gồm nhiều lớp. Việc không phân biệt các lớp đó là lý do bạn không thể giải thích tại sao document biến mất.

2. Prerequisites (Yêu cầu đầu vào) ​

Không có. Đây là lesson đầu tiên của curriculum.

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

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

  1. Phân biệt ECMAScript, JavaScript Engine, và Host Environment.
  2. Phân loại một API là language feature hay host API.
  3. Giải thích tại sao cùng một đoạn code cho kết quả khác nhau ở Browser và Node.js.
  4. Dự đoán behavior đơn giản dựa trên runtime environment.

4. Mental Model ​

Hãy hình dung JavaScript hoạt động qua 4 lớp:

Four layers of JavaScript execution: ECMAScript Specification, JavaScript Engine, Host Environment, and Host APIs.

Mental Model (Mô hình tư duy)

  • ECMAScript là bộ quy tắc (specification). Nó định nghĩa các quy tắc và semantics của ngôn ngữ JavaScript: syntax, types, operators, functions, objects, control flow, built-in objects... Nó không phải code chạy được mà là mô tả semantics — code phải có hành vi như thế nào.
  • JavaScript Engine là chương trình thực tế (V8 trong Chrome/Node.js, SpiderMonkey trong Firefox, JavaScriptCore trong Safari). JavaScript Engine là implementation của ngôn ngữ ECMAScript. Nó parse, compile/interpret và execute JavaScript code theo semantics được specification định nghĩa.
  • Host Environment là nền tảng cung cấp "sân chơi" cho engine: Browser cung cấp DOM, Node.js cung cấp fs và process.
  • Host APIs là các API do Host Environment cung cấp để JavaScript tương tác với môi trường bên ngoài language core. Ví dụ, Browser cung cấp document, DOM APIs, timers và Web APIs; Node.js cung cấp các API như fs và process.

Quan trọng: Array.prototype.map thuộc ECMAScript, nên JavaScript Engine phải implement nó theo specification. Ngược lại, document không thuộc ECMAScript; nó là API do Browser cung cấp. Vì vậy, một JavaScript Engine không tự động cung cấp document.

5. Core Concepts (Các khái niệm cốt lõi) ​

Essential — Bắt buộc nắm vững ​

Khái niệmĐịnh nghĩa
ECMAScriptBộ specification chuẩn hóa phần core language của JavaScript. Được duy trì bởi TC39.
JavaScript EngineChương trình thực thi JavaScript source code theo ECMAScript spec.
Host EnvironmentNền tảng (Browser, Node.js, v.v.) cung cấp runtime context và APIs bên ngoài language core.
RuntimeTổng thể: Engine + Host Environment + các APIs sẵn có tại thời điểm chạy.

Supporting — Cần biết để hiểu context ​

  • Các engine phổ biến: V8 (Chrome, Edge, Node.js), SpiderMonkey (Firefox), JavaScriptCore (Safari).
  • Các host phổ biến: Browser, Node.js, Deno, Bun.

Awareness — Biết tồn tại, chưa cần master ​

  • TC39, ECMA-262, và chu kỳ release hàng năm (ES2015, ES2023, v.v.).
  • Engine có thể implement spec với các tối ưu khác nhau.

Out of Scope — Không học trong bài này ​

Out of Scope

  • JIT compilation, hidden classes, inline caching → Stage 11
  • Garbage Collector internals → Stage 11
  • Execution Context, Lexical Environment → Stage 1
  • Module system (ESM/CJS) → Stage 7

6. Worked Example (Ví dụ phân tích từng bước) ​

Hãy cùng phân tích từng bước: document là gì?

js
console.log(typeof document);

Bước 1 — Nhận diện token: document là một identifier (tên biến/tên API).

Bước 2 — Tra cứu: Engine tìm document trong global scope.

Bước 3 — Kiểm tra nguồn gốc: document không nằm trong ECMAScript spec. Nó không được định nghĩa là một built-in của language core.

Bước 4 — Kiểm tra Host: Browser cung cấp document như một global object đại diện cho DOM tree. Node.js không cung cấp DOM, nên không có document.

Bước 5 — Kết luận:

  • Browser → typeof document === "object"
  • Node.js → typeof document === "undefined"

Code Review Lens

Khi review code, hãy tự hỏi: "API này thuộc lớp nào?" Nếu bạn thấy document hoặc window trong một file utility "tưởng chừng pure (không phụ thuộc vào môi trường bên ngoài)", đó là red flag cho SSR hoặc unit test.

7. Prediction Exercise (Bài tập dự đoán) ​

Đừng chạy code. Đọc và dự đoán kết quả, sau đó giải thích tại sao.

Câu 1 — Trong Browser:

js
console.log(typeof Array);
console.log(typeof fetch);
console.log(typeof process);

Câu 2 — Trong Node.js:

js
console.log(typeof Array);
console.log(typeof fetch);
console.log(typeof process);

Câu 3 — Trong cả hai:

js
console.log(typeof (() => {}));

Sau khi dự đoán xong, mở DevTools (Browser) và terminal (Node.js) để verify. Nếu sai, quay lại Mental Model ở Section 4.

[Đáp án & Giải thích]

Câu 1 — Browser:

  • typeof Array → "function" — Array là built-in constructor, thuộc ECMAScript language layer (Lớp 1), nên có ở mọi engine.
  • typeof fetch → "function" — fetch là Host API (Lớp 4) do Browser cung cấp để gọi HTTP request.
  • typeof process → "undefined" — process là Host API của Node.js (Lớp 3–4), Browser không cung cấp.

Câu 2 — Node.js:

  • typeof Array → "function" — Tương tự Câu 1, language feature nên luôn có.
  • typeof fetch → "function" (Node.js 18+) hoặc "undefined" (Node.js < 18) — fetch vốn là Browser Host API, nhưng từ Node.js 18 được "mượn" vào runtime. Vẫn là Host API, không phải language feature.
  • typeof process → "object" — process là Host API đặc trưng của Node.js, cung cấp thông tin và điều khiển tiến trình.

Câu 3 — Cả hai:

  • typeof (() => {}) → "function" — Arrow function là syntax của ECMAScript spec (Lớp 1), engine nào cũng phải hỗ trợ. Kết quả không đổi dù chạy ở đâu.

8. Implementation Lab (Bài lab thực hành) ​

Mục tiêu: Viết một hàm đơn giản để detect environment.

js
function detectEnvironment() {
  if (typeof document !== "undefined") {
    return "browser";
  }
  if (typeof process !== "undefined") {
    return "node";
  }
  return "unknown";
}

console.log(detectEnvironment());

TIP

typeof someVariable an toàn ngay cả khi someVariable chưa được khai báo. Đây là lý do ta dùng typeof thay vì if (document) — vì document không tồn tại sẽ throw ReferenceError.

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

Edge Case 1: fetch đã "di cư" ​

fetch từng là API chỉ có trong Browser. Từ Node.js 18+, fetch được cung cấp như một global Web API.

Sai lầm phổ biến

Điều này không có nghĩa fetch là language feature. Nó vẫn là Host API — chỉ là Node.js quyết định "mượn" API đó từ Web platform. Nếu bạn nhầm fetch là ECMAScript built-in, bạn sẽ bối rối khi gặp environment không hỗ trợ nó.

Edge Case 2: globalThis ​

js
console.log(globalThis);
  • Browser → trỏ đến window
  • Node.js → trỏ đến global
  • Web Worker → trỏ đến self

globalThis là language feature (ECMAScript 2020) giúp truy cập global object một cách nhất quán cross-environment.

10. Debug Lab (Bài lab gỡ lỗi) ​

Symptom (Triệu chứng): Bạn chạy một script bằng Node.js và nhận lỗi:

js
ReferenceError: document is not defined

Reproduction (Tái hiện lỗi):

js
// utils.js
export function getTitle() {
  return document.title;
}
js
// test.js (chạy bằng Node.js)
import { getTitle } from "./utils.js";
console.log(getTitle());

Evidence (Bằng chứng): Stack trace chỉ ra dòng return document.title;.

Hypothesis (Giả thuyết): document là Browser API. Node.js runtime không cung cấp DOM.

Verification (Xác minh): Chạy console.log(typeof document) trong Node.js → "undefined".

Root Cause (Nguyên nhân gốc rễ): Confusion giữa language layer và host layer. Code giả định DOM tồn tại nhưng đang chạy trong host không có DOM.

Fix: Tách logic phụ thuộc DOM ra một module riêng, hoặc guard:

js
export function getTitle() {
  if (typeof document === "undefined") {
    return null; // hoặc throw domain-specific error
  }
  return document.title;
}

Prevention (Phòng ngừa): Luôn hỏi "API này thuộc host nào?" trước khi viết code dùng chung giữa client và server.

11. Design Exercise (Bài tập thiết kế giải pháp) ​

Không áp dụng ở depth L2–L3. Design exercise sẽ xuất hiện từ các lesson L5+.

12. Production Scenario (Tình huống thực tế) ​

Context: Bạn đang làm một ứng dụng Next.js (SSR). Component Header cần đọc window.location.pathname để highlight tab đang active.

Symptom: Server render bị crash với window is not defined.

Câu hỏi:

  1. Tại sao window không tồn tại khi server render?
  2. Bạn nên guard như thế nào?
  3. Đây là lỗi ở lớp nào của mental model?
Gợi ý

window là Browser Host API. Server (Node.js) không có window. Bạn phải đảm bảo code truy cập window chỉ chạy ở client-side, hoặc dùng typeof window !== "undefined".

Đây là lỗi lớp 3–4 (Host Environment), không phải lỗi lớp 1–2 (ECMAScript/Engine).

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

Level A — Ask

  1. Tự viết một đoạn giải thích: "ECMAScript và JavaScript khác nhau thế nào?"
  2. Hỏi AI cùng câu hỏi đó.
  3. So sánh câu trả lời của bạn với AI.
  4. Tìm ít nhất một điểm AI nói sai hoặc quá mơ hồ.

Gợi ý

AI thường nói "ECMAScript là tiêu chuẩn, JavaScript là implementation". Hãy kiểm tra xem AI có nhấn mạnh vai trò của Host Environment và Host APIs không. Nếu không, bạn hiểu sâu hơn AI ở khía cạnh này.

Đáp án tham khảo
  • Bạn nghĩ

ECMAScript là specification — bộ quy tắc chuẩn. JavaScript Engine là thằng thực thi code theo bộ quy tắc đó. Nhưng engine không tự sinh ra document hay process. Browser và Node.js mới là thằng cung cấp mấy thứ đó. Nên nếu không phân biệt được lớp nào thuộc về ai, mình sẽ không hiểu tại sao code chạy chỗ này được mà chỗ kia lỗi.

  • AI trả lời

ECMAScript là tiêu chuẩn (specification) định nghĩa các đặc điểm cốt lõi của ngôn ngữ. JavaScript là ngôn ngữ được triển khai dựa trên tiêu chuẩn ECMAScript. Các engine như V8, SpiderMonkey hay JavaScriptCore implement ECMAScript để thực thi code JavaScript.

Tuy nhiên, JavaScript không chỉ có phần được định nghĩa bởi ECMAScript. Khi chạy trong một Host Environment như Browser hoặc Node.js, JavaScript còn có thể sử dụng các Host APIs do môi trường đó cung cấp. Ví dụ, Browser cung cấp DOM, fetch() và nhiều Web APIs; Node.js cung cấp process, fs và các API riêng của Node.js.

Vì vậy, nếu code sử dụng document trong Node.js, hoặc sử dụng process trong một môi trường không cung cấp API này, code có thể không chạy. Muốn hiểu JavaScript sâu hơn, cần phân biệt rõ ECMAScript → JavaScript Engine → Host Environment → Host APIs.

  • So sánh

Câu trả lời của AI đúng ở ý chính: ECMAScript là specification, còn các engine như V8 là implementation. Tuy nhiên, câu trả lời ban đầu dễ bị quá đơn giản nếu chỉ nói “ECMAScript là tiêu chuẩn, JavaScript là implementation”.

Điểm quan trọng cần bổ sung là Host Environment và Host APIs. Đây là lý do cùng một đoạn JavaScript nhưng có thể chạy được trong Browser mà lại lỗi trong Node.js, hoặc ngược lại.

  • Điểm AI nói sai hoặc quá mơ hồ

Câu “JavaScript là implementation của ECMAScript” không hoàn toàn chính xác nếu hiểu theo nghĩa JavaScript chỉ là một implementation duy nhất. Thực tế, nhiều engine khác nhau implement specification của ECMAScript để thực thi JavaScript.

Ngoài ra, document, fetch(), process, fs... không phải tất cả đều thuộc về ECMAScript. Chúng phụ thuộc vào host environment đang chạy JavaScript.

  • Kết luận: Có thể hình dung đơn giản

    text
    ECMAScript
        ↓
    Specification của ngôn ngữ
        ↓
    JavaScript Engine
    (V8, SpiderMonkey, JavaScriptCore...)
        ↓
    Thực thi JavaScript
        ↓
    Host Environment
    (Browser, Node.js, ...)
        ↓
    Host APIs
    (DOM, fetch, process, fs, ...)

14. Teach Back (Dạy lại) ​

Trong 2 phút, giải thích cho một đồng nghiệp:

"Tại sao cùng một file JavaScript, chạy trong Browser thì typeof document === "object", nhưng chạy trong Node.js thì typeof document === "undefined"?"

Yêu cầu:

  • Dùng đúng terminology: ECMAScript, Engine, Host, Runtime.
  • Không được nói "Node.js không hỗ trợ document" mà không giải thích tại sao.
  • Vẽ (hoặc mô tả) 4 lớp mental model.
Mô phỏng
  • Bạn nói

JavaScript có 4 layer execution: ECMAScript Specification, JavaScript Engine, Host Environment và Host APIs.

ECMAScript layer là bộ quy tắc (specification). Nó định nghĩa rules và semantics của ngôn ngữ JavaScript, nhưng không phải code chạy được.

Để thực thi code thì có JavaScript Engine — đây là implementation của ECMAScript. Engine sẽ parse, compile/interpret và execute code theo semantics mà specification định nghĩa.

Khi Engine đọc đoạn typeof document, nó nhận diện document là một identifier và cần resolve nó trong global environment. document không được ECMAScript định nghĩa là built-in của language core, cho nên có thể suy ra nó đến từ nơi khác: Host Environment.

Nếu Host là Browser, Browser cung cấp Host APIs, trong đó có DOM API và global object document, đại diện cho DOM của trang web. Vì vậy typeof document === "object".

Còn nếu Host là Node.js, Node.js không cung cấp DOM API hay document. Vì vậy document không tồn tại, và typeof document === "undefined".

Nói chung thì: Engine chịu trách nhiệm chạy JavaScript theo ECMAScript; Host quyết định môi trường đó cung cấp thêm những API gì. Browser có DOM nên có document, Node.js không có DOM nên không có document.

💡 Dễ nhớ: ECMAScript giống như luật chơi, Engine giống như người biết chơi theo luật, còn Host Environment giống như sân chơi. Cùng một người chơi và cùng một luật, nhưng vào sân Browser thì được phát cho document, window, DOM; vào sân Node.js thì được phát fs, process, Buffer. Người chơi không thay đổi, luật không thay đổi — chỉ là sân chơi cung cấp "vật phẩm" khác nhau.

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

  • Đồng nghiệp có tự dự đoán được typeof window trong Node.js không?
  • Họ có hiểu tại sao Array thì có ở cả hai mà document thì không?
  • Nếu họ hỏi lại "vậy fetch thì sao?" — bạn giải thích được không?

15. Assessment (Đánh giá) ​

Objective (Mục tiêu)Hình thức đánh giá
Phân biệt ECMAScript / Engine / HostClassification (Phân loại) — 8/10 API phân loại đúng
Dự đoán environment-specific behaviorPrediction (Dự đoán) — 3/3 scenarios đúng
Giải thích lỗi document is not definedExplain (Giải thích) — dùng mental model 4 lớp
Detect runtime an toànImplementation (Thực hiện) — typeof guard đúng

16. Exit Criteria (Tiêu chí qua bài) ​

Bạn PASS lesson này khi:

  • [ ] Có thể phân biệt ECMAScript, JavaScript Engine, và Host Environment.
  • [ ] Có thể phân loại một API bất kỳ thành language feature hoặc host API.
  • [ ] Có thể dự đoán đúng behavior của typeof với global APIs ở 2 environment khác nhau.
  • [ ] Có thể giải thích lỗi document is not defined bằng mental model 4 lớp, thay vì chỉ đoán theo trực giác (intuition).
  • [ ] Có thể viết guard check an toàn bằng typeof để tránh ReferenceError.

17. Spiral Connection (Liên kết xoắn ốc) ​

Previous (Trước) → Không có. Đây là lesson đầu tiên của toàn bộ curriculum.

Current (Hiện tại) → Mental model 4 lớp: ECMAScript → Engine → Host → APIs

Next (Tiếp theo)

→ Lesson 0.1.2: Browser vs Node.js (đi sâu vào từng host)

→ Stage 1: Execution Model (đi sâu vào Engine layer)

→ Stage 4: Browser Runtime (đi sâu vào Host APIs)

→ Stage 11: Performance & Engine Internals (JIT, GC, Hidden Classes)

Thông tin

Mental model bạn học hôm nay sẽ được tái sử dụng liên tục. Khi học Closure (Stage 1), bạn sẽ hiểu Engine quản lý scope như thế nào. Khi học React SSR (Stage 10), bạn sẽ quay lại câu hỏi: "API này thuộc host nào?" Đây chính là spiral learning.

📴 Offline Mode — Content served from cache