Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Cách khai báo biến Block-Scoped trong JavaScript

Biến Block-Scoped với let và const (ES2015)

Trước ES2015, JavaScript chỉ có var (function-scoped). ES6 giới thiệu let và const cho block scope (phạm vi khối) - biến chỉ tồn tại trong cặp { } gần nhất.

Ví dụ minh họa

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Block Scoped Variables</title>
    <style>
        body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
        .result, .sample { font-size: 18px; font-weight: 500; font-family: monospace; }
        .result { color: green; }
        button { padding: 8px 16px; cursor: pointer; }
    </style>
</head>
<body>
    <h1>Khai báo biến Block-Scoped</h1>
    <div class="sample"></div>
    <div class="result"></div>
    <button class="btn-demo">KIỂM TRA PHẠM VI</button>
    <h3>Nhấn nút để khai báo và kiểm tra biến block-scoped</h3>

    <script>
        const resEle = document.querySelector(".result");
        const sampleEle = document.querySelector(".sample");
        const btn = document.querySelector(".btn-demo");

        // Khối lệnh { } tạo block scope mới
        {
            let a = 22;
            const b = 44;
            sampleEle.textContent = `Trong block:\nlet a = ${a}\nconst b = ${b}`;
        }

        // a và b KHÔNG truy cập được ở đây
        btn.addEventListener("click", () => {
            try {
                // Tham chiếu a, b ngoài block -> ReferenceError
                const sum = a + b;
                resEle.textContent = `a + b = ${sum}`;
            } catch (err) {
                resEle.textContent = `Lỗi: ${err.message}\n(Biến a, b chỉ tồn tại trong block { })`;
            }
        });
    </script>
</body>
</html>

So sánh var vs let/const - Phạm vi

function demo() {
    if (true) {
        var x = 1;      // function-scoped
        let y = 2;      // block-scoped
        const z = 3;    // block-scoped
    }
    
    console.log(x); // 1 - var "rò rỉ" ra ngoài block
    // console.log(y); // ReferenceError - let bị chặn bởi block
    // console.log(z); // ReferenceError - const bị chặn bởi block
}

Ví dụ thực tế: Vòng lặp

// Vấn đề với var
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log('var:', i), 100); // In ra: 3, 3, 3
}

// Giải quyết với let (mỗi lần lặp tạo binding mới)
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log('let:', i), 100); // In ra: 0, 1, 2
}

// const trong vòng lặp for...of
for (const item of ['a', 'b', 'c']) {
    console.log(item); // OK, binding mới mỗi lần lặp
}
// for (const i = 0; i < 3; i++) {} // LỖI: const không thể gán lại i++

Temporal Dead Zone (TDZ)

Khoảng từ đầu block đến dòng khai báo let/const gọi là TDZ. Truy cập biến trong TDZ ném ReferenceError:

{
    console.log(x); // ReferenceError
    let x = 10;
}

Best Practice

  1. Luôn dùng const mặc định.
  2. Dùng let khi cần gán lại.
  3. Khai báo biến ở đầu block (hoặc ngay trước khi dùng) để tránh TDZ.
  4. Dùng block { } tường minh để giới hạn scope khi cần.