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

Symbol trong JavaScript

Khái niệm

Symbol (ES2015) là kiểu dữ liệu nguyên thủy (primitive) duy nhất, bất biến, và hoàn toàn unique. Dùng làm key cho object property để tránh xung đột tên, đặc biệt khi mở rộng thư viện/third-party code.

Đặc điểm

  • Tạo bằng Symbol() (không dùng new)
  • Mỗi lần gọi Symbol() tạo giá trị khác nhau
  • Không tự động chuyển đổi sang string
  • Không xuất hiện trong for...in, Object.keys(), JSON.stringify()

Ví dụ cơ bản

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript Symbols</title>
    <style>
        body { font-family: 'Segoe UI', sans-serif; padding: 20px; }
        .result { font-size: 16px; color: #6a1b9a; font-weight: 500; margin: 20px 0; padding: 15px; background: #f3e5f5; border-radius: 4px; min-height: 100px; white-space: pre-wrap; }
        button { padding: 10px 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; }
    </style>
</head>
<body>
    <h1>Symbol trong JavaScript</h1>
    <div class="result" id="result"></div>
    <button id="btn">HIỂN THỊ & SO SÁNH SYMBOL</button>
    <h3>Nhấn nút để hiển thị và so sánh Symbol</h3>

    <script>
        const btnEle = document.getElementById('btn');
        const resEle = document.getElementById('result');

        // Tạo Symbol
        const sym1 = Symbol('test');
        const sym2 = Symbol('test');
        const sym3 = Symbol.for('shared'); // Global symbol registry
        const sym4 = Symbol.for('shared'); // Cùng key -> cùng Symbol

        btnEle.addEventListener('click', () => {
            resEle.textContent = '';
            
            // Hiển thị Symbol
            resEle.textContent += `sym1: ${sym1.toString()}\n`;
            resEle.textContent += `sym2: ${sym2.toString()}\n`;
            resEle.textContent += `sym3 (for): ${sym3.toString()}\n`;
            resEle.textContent += `sym4 (for): ${sym4.toString()}\n\n`;
            
            // So sánh
            resEle.textContent += `sym1 === sym2: ${sym1 === sym2}\n`; // false - unique
            resEle.textContent += `sym3 === sym4: ${sym3 === sym4}\n`; // true - global registry
            
            // Dùng làm key object
            const obj = {
                [sym1]: 'Giá trị riêng',
                [Symbol('id')]: 123,
                name: 'Public'
            };
            
            resEle.textContent += `\nObject keys: ${Object.keys(obj)}`; // Chỉ ['name']
            resEle.textContent += `\nOwnPropertySymbols: ${Object.getOwnPropertySymbols(obj).map(s => s.toString())}`;
            resEle.textContent += `\nobj[sym1]: ${obj[sym1]}`;
        });
    </script>
</body>
</html>

Kết quả

sym1: Symbol(test)
sym2: Symbol(test)
sym3 (for): Symbol(for shared)
sym4 (for): Symbol(for shared)

sym1 === sym2: false
sym3 === sym4: true

Object keys: name
OwnPropertySymbols: Symbol(test), Symbol(id)
obj[sym1]: Giá trị riêng

Symbol nổi tiếng (Well-known Symbols)

JS định nghĩa sẵn các Symbol để tùy chỉnh hành vi built-in:

SymbolMục đích
Symbol.iteratorLàm object iterable (dùng cho for...of)
Symbol.toPrimitiveTùy chỉnh chuyển đổi sang primitive
Symbol.toStringTagTùy chỉnh Object.prototype.toString()
Symbol.hasInstanceTùy chỉnh instanceof
Symbol.asyncIteratorAsync iterable (for await...of)

Ví dụ: Custom Iterator

const range = {
    from: 1,
    to: 5,
    [Symbol.iterator]() {
        let current = this.from;
        return {
            next() {
                return current <= this.to 
                    ? { value: current++, done: false }
                    : { done: true };
            }
        };
    }
};

for (const num of range) {
    console.log(num); // 1, 2, 3, 4, 5
}