Symbol 是 ECMAScript 6 (ES6) 引入的一种新的原始数据类型,它是 JavaScript 的第七种数据类型(前六种是:Undefined、Null、Boolean、String、Number 和 Object)。
基本概念
创建 Symbol
javascript
javascript
// 创建一个 Symbol
let sym1 = Symbol();
let sym2 = Symbol('description'); // 可选的描述字符串
console.log(typeof sym1); // "symbol"
console.log(sym2.toString()); // "Symbol(description)"
特性
-
唯一性 :每个 Symbol 都是唯一的,即使描述相同 javascript
inilet sym1 = Symbol('foo'); let sym2 = Symbol('foo'); console.log(sym1 === sym2); // false
-
不可枚举性 :Symbol 属性默认不会出现在
for...in
、Object.keys()
等枚举中 -
不可强制转换 :不能隐式转换为字符串或数字 javascript
javascriptlet sym = Symbol(); console.log("Symbol: " + sym); // TypeError console.log(Number(sym)); // TypeError
主要用途
1. 作为对象属性键
javascript
ini
const MY_KEY = Symbol();
let obj = {};
obj[MY_KEY] = 'secret value';
console.log(obj[MY_KEY]); // "secret value"
// 或者使用计算属性名
let obj2 = {
[MY_KEY]: 'another secret'
};
2. 定义类的私有成员
javascript
kotlin
const _counter = Symbol('counter');
const _action = Symbol('action');
class Countdown {
constructor(counter, action) {
this[_counter] = counter;
this[_action] = action;
}
dec() {
if (this[_counter] < 1) return;
this[_counter]--;
if (this[_counter] === 0) {
this[_action]();
}
}
}
3. 避免属性名冲突
javascript
ini
// 不同库可以安全地添加属性到对象上
const LIB1_PROP = Symbol('lib1 property');
const LIB2_PROP = Symbol('lib2 property');
let obj = {};
obj[LIB1_PROP] = 'Library 1 data';
obj[LIB2_PROP] = 'Library 2 data';
全局 Symbol 注册表
Symbol.for()
在全局 Symbol 注册表中创建或获取 Symbol:
javascript
ini
let sym1 = Symbol.for('shared');
let sym2 = Symbol.for('shared');
console.log(sym1 === sym2); // true
Symbol.keyFor()
获取全局 Symbol 的键:
javascript
javascript
let sym = Symbol.for('foo');
console.log(Symbol.keyFor(sym)); // "foo"
内置 Symbol
ES6 定义了一些内置的 Symbol 值,称为"知名 Symbol",用于实现特定的语言行为:
Symbol.iterator
:定义对象的默认迭代器Symbol.toStringTag
:自定义对象的toString()
行为Symbol.hasInstance
:自定义instanceof
操作符的行为Symbol.species
:指定创建派生对象的构造函数Symbol.toPrimitive
:将对象转换为原始值的方法Symbol.isConcatSpreadable
:配置对象作为Array.prototype.concat()
的参数时是否展开其元素
示例:实现可迭代对象
javascript
javascript
const myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
};
for (let value of myIterable) {
console.log(value); // 1, 2, 3
}
注意事项
- Symbol 不能使用
new
操作符(不是构造函数) - Symbol 值不能与其他类型的值进行运算
- Symbol 作为属性名时,必须使用方括号语法(不能使用点操作符)
- 使用
Object.getOwnPropertySymbols()
可以获取对象的所有 Symbol 属性
Symbol 提供了一种创建唯一标识符的机制,非常适合用于需要避免命名冲突的场景,特别是在大型项目和库的开发中。