第 33 章 Symbol

第 33 章 Symbol

Symbol 是 ES6 引入的一种新数据类型,代表一个"独一无二"的值。就像每个人都有自己的身份证号一样,每个 Symbol 都是唯一的。

33.1 Symbol 基础

Symbol():创建独一无二的值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 创建 Symbol
const s1 = Symbol();
const s2 = Symbol();

console.log(s1 === s2); // 打印结果: false(每次 Symbol() 都是独一无二的)

// Symbol 可以有描述
const s3 = Symbol('mySymbol');
const s4 = Symbol('mySymbol');

console.log(s3 === s4); // 打印结果: false(描述相同,但值不同)
console.log(s3.description); // 打印结果: mySymbol

Symbol.for / Symbol.keyFor:全局注册表

Symbol.for 创建在全局注册表中的 Symbol,同一个 key 会返回同一个 Symbol。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Symbol.for:在全局注册表中查找或创建
const s1 = Symbol.for('globalSymbol');
const s2 = Symbol.for('globalSymbol');

console.log(s1 === s2); // 打印结果: true(同一个 key 返回同一个值)

// Symbol.keyFor:从全局注册表中获取 key
const key = Symbol.keyFor(s1);
console.log(key); // 打印结果: globalSymbol

// 普通 Symbol 不在全局注册表中
const s3 = Symbol('notGlobal');
console.log(Symbol.keyFor(s3)); // 打印结果: undefined

Symbol 不可枚举

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const obj = {
    name: '小明',
    age: 18
};

const secret = Symbol('secret');
obj[secret] = '隐藏的信息';

console.log(Object.keys(obj)); // 打印结果: ['name', 'age'](Symbol 属性不可枚举)
console.log(Object.getOwnPropertySymbols(obj)); // 打印结果: [Symbol(secret)]

下一节,我们来学习内置 Symbol!

33.2 内置 Symbol

Symbol.iterator:可迭代协议

Symbol.iterator 让对象变成可迭代的,可以用 for…of 遍历。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const myArray = {
    items: ['苹果', '香蕉', '橙子'],
    [Symbol.iterator]: function() {
        let index = 0;
        const self = this;
        return {
            next: function() {
                if (index < self.items.length) {
                    return {
                        value: self.items[index++],
                        done: false
                    };
                }
                return { done: true };
            }
        };
    }
};

for (const item of myArray) {
    console.log(item); // 打印结果: 苹果 香蕉 橙子
}

Symbol.toStringTag:自定义 toString 结果

1
2
3
4
5
const person = {
    [Symbol.toStringTag]: 'Person'
};

console.log(Object.prototype.toString.call(person)); // 打印结果: [object Person]

Symbol.hasInstance:自定义 instanceof 行为

1
2
3
4
5
6
7
8
class Even {
    static [Symbol.hasInstance](instance) {
        return typeof instance === 'number' && instance % 2 === 0;
    }
}

console.log(2 instanceof Even); // 打印结果: true
console.log(3 instanceof Even); // 打印结果: false

Symbol.toPrimitive:自定义类型转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const obj = {
    value: 42,
    [Symbol.toPrimitive](hint) {
        if (hint === 'number') {
            return this.value;
        }
        if (hint === 'string') {
            return String(this.value);
        }
        return this.value;
    }
};

console.log(+obj); // 打印结果: 42(hint = 'number')
console.log(String(obj)); // 打印结果: 42(hint = 'string')
console.log(obj + ''); // 打印结果: 42(hint = 'default')

Symbol.replace / Symbol.split:自定义字符串方法

1
2
3
4
5
6
7
const replacer = {
    [Symbol.replace](target, replacement) {
        return target.toUpperCase().replace('HELLO', replacement);
    }
};

console.log('hello'.replace(replacer, 'Hi')); // 打印结果: Hi

Symbol.isConcatSpreadable:控制 concat 展开

1
2
3
4
5
6
7
8
9
const array = [1, 2];
const likeArray = {
    0: 'a',
    1: 'b',
    length: 2,
    [Symbol.isConcatSpreadable]: true
};

console.log([].concat(array, likeArray)); // 打印结果: [1, 2, 'a', 'b']

本章小结

本章我们学习了 Symbol:

  1. Symbol 基础:创建独一无二的值,Symbol.for/keyFor 全局注册表,不可枚举。
  2. 内置 Symbol:Symbol.iterator、Symbol.toStringTag、Symbol.hasInstance、Symbol.toPrimitive 等,让对象具有特殊行为。

Symbol 是 JavaScript 的"秘密武器",可以创建独一无二的属性名,避免属性名冲突,是实现协议和元编程的重要工具。

下一章,我们要学习正则表达式——字符串匹配的"神器"!