Symbol
是什么?
Symbol
是一个基本类型,用于生成唯一的标识符。每次调用 Symbol()
函数,都会创建一个新的、唯一的 Symbol
值,即使传递相同的描述(description),它们也不会相等。
let symbol1 = Symbol('example');
let symbol2 = Symbol('example');
console.log(symbol1 === symbol2); // false,每个 Symbol 都是唯一的
如何创建 Symbol
?
可以使用 Symbol()
函数创建 Symbol
,它可以带一个可选的描述(通常用于调试目的,不影响唯一性)。
let sym1 = Symbol();
let sym2 = Symbol('description');
console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)
Symbol
作为对象属性的键
Symbol
常用于对象属性的键,因为它是唯一的,避免了属性名冲突问题。普通的字符串属性名可能会被重写,但 Symbol
保证唯一性。
let uniqueKey = Symbol('unique');
let myObject = {
[uniqueKey]: 'value'
};
console.log(myObject[uniqueKey]); // 'value'
console.log(myObject.uniqueKey); // undefined,因为 Symbol 不是字符串
Symbol
的特性
- 唯一性:每一个
Symbol
都是唯一的,即使描述相同也不相等。 - 不可改变:
Symbol
是不可变的,不像对象可以更改内容。 - 非枚举属性:使用
Symbol
作为属性名时,该属性默认是不可枚举的,不会被for...in
或Object.keys()
枚举。可以使用Object.getOwnPropertySymbols
获取
let hiddenKey = Symbol('hidden');
let person = {
name: 'John',
age: 30,
[hiddenKey]: 'Secret'
};
// 使用 for...in 枚举属性时不会显示 Symbol
for (let key in person) {
console.log(key); // 'name', 'age'
}
console.log(Object.keys(person)); // ['name', 'age']
console.log(Object.getOwnPropertySymbols(person)); // [Symbol(hidden)]
Symbol
的内置方法和属性
Symbol.for()
和 Symbol.keyFor()
Symbol.for()
方法可以在全局注册表中创建和重用 Symbol
,以便不同的模块中可以共享同一个 Symbol
。而 Symbol.keyFor()
可以通过全局 Symbol
查找其键。只针对Symbol.for()
方法创建的Symbol
才能找到其键。
let globalSym1 = Symbol.for('shared');
let globalSym2 = Symbol.for('shared');
console.log(globalSym1 === globalSym2); // true,引用的是同一个 Symbol
console.log(Symbol.keyFor(globalSym1)); // 'shared'
console.log(Symbol.keyFor(Symbol('not shared'))); // undefined
Symbol
内置的静态属性
Symbol
提供了一些内置的静态属性,称为内置 Symbol
,通常用于 JavaScript 内部的操作,它们的用途如下:
Symbol.iterator
:用于定义对象的迭代器,可以使用for...of
进行遍历。Symbol.hasInstance
:自定义instanceof
操作符的行为。Symbol.toStringTag
:定义Object.prototype.toString.call
方法返回的值。Symbol.isConcatSpreadable
:用于控制Array.prototype.concat
方法是否可以展开对象。Symbol.species
:定义派生对象使用的构造函数。Symbol.toPrimitive
:定义对象转换为基本类型时的默认行为。
// Symbol.iterator 例子
let iterableObj = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
let data = this.data;
return {
next() {
return {
value: data[index++],
done: index > data.length
};
}
};
}
};
for (let value of iterableObj) {
console.log(value); // 1, 2, 3
}
// Symbol.toStringTag 例子
class CustomClass {
get [Symbol.toStringTag]() {
return 'CustomClass';
}
}
let instance = new CustomClass();
console.log(Object.prototype.toString.call(instance)); // [object CustomClass]
Symbol.iterator
返回的对象可以通过next()方法陆续返回值。也可以隐式地通过生成器函数返回:
class Emitter {
constructor(max) {
this.max = max;
this.idx = 0;
}
*[Symbol.iterator]() {
while(this.idx < this.max) {
yield this.idx++;
}
}
}
function count() {
let emitter = new Emitter(5);
for (const x of emitter) {
console.log(x);
}
}
count();
// 0
// 1
// 2
// 3
// 4
Symbol.replace
- 这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符串中匹配的子串。由
String.prototype.replace()
方法使用” String.prototype.replace()
会调用Symbol.replace
为键的方法来正则求值- 正则表达式原型上也有
Symbol.replace
这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符串中匹配的子串。由String.prototype.replace()方法使用”
String.prototype.replace() 会调用 Symbol.replace 为键的方法来正则求值
正则表达式原型上也有 Symbol.replace
这个方法传入非正则表达式值会导致该值被转换为RegExp
对象,可以重新定义Symbol.replace
函数取代默认对正则表达式求值的行为。
Symbol.replace
函数接收两个参数,即调用replace()
方法的字符串实例和替换字符串
class FooReplacer {
static [Symbol.replace](target, replacement) {
return target.split('foo').join(replacement);
}
}
console.log('barfoobaz'.replace(FooReplacer, 'qux')); // "barquxbaz"
class StringReplacer {
constructor(str) {
this.str = str;
}
[Symbol.replace](target, replacement) {
return target.split(this.str).join(replacement);
}
}
console.log('barfoobaz'.replace(new StringReplacer('foo'), 'qux')); // "barquxbaz"
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容