Hiểu Rõ Scope Trong JavaScript: Phân Biệt Global, Function, Block, Lexical

Bạn mới học JavaScript và thường xuyên gặp lỗi “không tìm thấy biến”, “biến bị ghi đè”, hoặc không hiểu vì sao một số biến lại không truy cập được? Tất cả đều liên quan đến khái niệm Scope – phạm vi hoạt động của biến trong JavaScript. Bài viết này sẽ giúp bạn hiểu rõ các loại scope, cách hoạt động và tránh lỗi thường gặp!

1. Scope là gì?

Scope (phạm vi) là vùng mà trong đó một biến có thể “sống” và được truy cập trong code. Nói đơn giản, scope quyết định bạn có thể sử dụng biến ở đâu trong chương trình.

2. Các loại scope trong JavaScript

JavaScript có 4 loại scope chính:

Tên ScopeMô tả đơn giản
Global ScopeBiến nằm ngoài hàm, dùng được ở bất kỳ đâu
Function ScopeBiến nằm trong hàm, chỉ dùng trong hàm đó
Block ScopeBiến nằm trong { ... }, chỉ dùng trong block đó
Lexical ScopeBiến truy cập theo thứ tự lồng nhau của các hàm/block

2.1. Global Scope – Biến toàn cục

Biến được khai báo ngoài tất cả các hàm hoặc block sẽ thuộc global scope. Bạn có thể truy cập biến này từ bất kỳ đâu trong code.

var x = 10;

function showX() {
  console.log(x); // ✅ In ra 10 vì x là global
}
showX();
console.log(x); // ✅ In ra 10

Lưu ý: Biến global dễ bị ghi đè hoặc xung đột nếu đặt trùng tên.

2.2. Function Scope – Phạm vi trong hàm

Biến khai báo bằng var trong một hàm chỉ tồn tại trong hàm đó.

function demo() {
  var name = "Tèo";
  console.log(name); // ✅ OK
}
demo();
console.log(name); // ❌ ReferenceError: name is not defined

Biến function scope sẽ “chết” khi ra khỏi hàm.

2.3. Block Scope – Phạm vi trong { … }

Biến khai báo bằng let hoặc const chỉ tồn tại trong block { ... } gần nhất.

if (true) {
  let age = 30;
  console.log(age); // ✅ OK
}
console.log(age); // ❌ ReferenceError: age is not defined

Lợi ích: Ngăn lỗi sử dụng biến sai chỗ, giúp code an toàn hơn.

2.4. Lexical Scope – Phạm vi theo vị trí lồng nhau

Lexical scope nghĩa là hàm con có thể truy cập biến của hàm cha (theo thứ tự lồng nhau).

function outer() {
  const outerVar = "Tôi là ngoài";

  function inner() {
    console.log(outerVar); // ✅ Truy cập được
  }

  inner();
}
outer();

Lưu ý: Không truy cập được chiều ngược lại (hàm cha không thấy biến của hàm con).

3. Tư duy nhanh: Hình dung Scope như ngôi nhà

  • Global Scope = Cả ngôi nhà (ai cũng vào được)

  • Function Scope = Phòng kín (chỉ người trong phòng mới thấy đồ)

  • Block Scope = Ngăn tủ (chỉ ai đứng đúng chỗ mới mở được)

  • Lexical Scope = Phòng con thấy đồ phòng cha, nhưng không ngược lại

4. Vì sao phải hiểu Scope?

  • Tránh xung đột biến giữa các hàm, tránh bị ghi đè biến.

  • Bảo vệ biến, tránh rò rỉ dữ liệu (dùng letconst).

  • Hiểu cách closure hoạt động (vì lexical scope).

  • Hiểu rõ về hoisting (biến chỉ hoisting trong scope hiện tại).

5. Kiểm tra nhanh kiến thức

Bạn thử đoán kết quả đoạn code sau:

function run() {
  var a = 10;
  if (true) {
    var a = 20;
    let b = 30;
    const c = 40;
  }
  console.log(a); // ?
  console.log(b); // ?
  console.log(c); // ?
}
run();

Đáp án:

  • console.log(a); // 20 (vì var a bị ghi đè trong block)
  • console.log(b); // ReferenceError (b chỉ sống trong block)
  • console.log(c); // ReferenceError (c chỉ sống trong block)

Kết luận

Hiểu rõ về scope giúp bạn viết code JavaScript an toàn, tránh lỗi khó chịu và xây dựng được các ứng dụng phức tạp hơn. Nếu còn thắc mắc về scope hoặc muốn mình giải thích chi tiết từng ví dụ, hãy để lại bình luận nhé!