常用内置Symbols介绍
ECMAScript 6 引入了Symbol
原始类型,同时提供了一系列内置的Symbol
值(称为“Well-known Symbols”),用于扩展对象的行为。这些内置Symbol
作为对象属性的键,可以控制对象在特定操作下的表现方式,例如迭代、类型转换等。
Symbol.iterator
Symbol.iterator
定义了对象的默认迭代器,用于for...of
循环或展开运算符等场景。实现该方法的对象称为可迭代对象。
const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
console.log([...myIterable]); // [1, 2, 3]
for (const value of myIterable) {
console.log(value); // 依次输出 1, 2, 3
}
内置类型如Array
、String
、Map
、Set
等均默认实现了Symbol.iterator
。自定义类也可以通过实现该方法使其实例可迭代:
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const range = new Range(1, 5);
console.log([...range]); // [1, 2, 3, 4, 5]
Symbol.toStringTag
Symbol.toStringTag
用于定制对象调用Object.prototype.toString()
时返回的字符串标签。默认情况下,普通对象返回[object Object]
,而通过该属性可以修改这一行为。
const myObj = {
[Symbol.toStringTag]: 'MyCustomObject'
};
console.log(Object.prototype.toString.call(myObj)); // "[object MyCustomObject]"
内置类型利用此特性返回更有意义的标签:
console.log(Object.prototype.toString.call(new Map())); // "[object Map]"
console.log(Object.prototype.toString.call(new Set())); // "[object Set]"
Symbol.hasInstance
Symbol.hasInstance
用于自定义instanceof
操作符的行为。当执行obj instanceof Constructor
时,实际上会调用Constructor[Symbol.hasInstance](obj)
。
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false
Symbol.species
Symbol.species
指定派生对象的构造函数。当需要创建派生对象时(如Array.prototype.map()
返回新数组),会使用该属性指定的构造函数而非默认的。
class MyArray extends Array {
static get [Symbol.species]() {
return Array; // 覆盖默认返回的MyArray
}
}
const myArr = new MyArray(1, 2, 3);
const mapped = myArr.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
Symbol.toPrimitive
Symbol.toPrimitive
允许对象自定义类型转换行为。当对象需要被转换为原始值(如通过+
操作符或String()
函数)时,会调用该方法。
const temperature = {
value: 25,
unit: '°C',
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'string':
return `${this.value}${this.unit}`;
case 'number':
return this.value;
default:
return this.value.toString();
}
}
};
console.log(String(temperature)); // "25°C"
console.log(+temperature); // 25
console.log(temperature + 5); // 30
Symbol.isConcatSpreadable
Symbol.isConcatSpreadable
决定数组或类数组对象在Array.prototype.concat()
时是否展开其元素。默认情况下数组会展开,而类数组不会。
const arr1 = [1, 2];
const arr2 = [3, 4];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr1.concat(arr2)); // [1, 2, [3, 4]]
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
arrayLike[Symbol.isConcatSpreadable] = true;
console.log(['x'].concat(arrayLike)); // ['x', 'a', 'b']
Symbol.match
Symbol.match
允许对象自定义String.prototype.match()
的行为。正则表达式默认实现了此方法。
const customMatcher = {
[Symbol.match](string) {
return string.includes('hello') ? ['hello'] : null;
}
};
console.log('world hello'.match(customMatcher)); // ["hello"]
console.log('world'.match(customMatcher)); // null
Symbol.replace
Symbol.replace
定义String.prototype.replace()
的行为。接收原始字符串和替换值作为参数。
const customReplacer = {
[Symbol.replace](string, replacement) {
return string.split(' ').join(replacement);
}
};
console.log('a b c'.replace(customReplacer, '-')); // "a-b-c"
Symbol.search
Symbol.search
定制String.prototype.search()
方法。返回匹配的索引位置。
const customSearcher = {
[Symbol.search](string) {
return string.indexOf('ECMAScript');
}
};
console.log('Learn ECMAScript 6'.search(customSearcher)); // 6
Symbol.split
Symbol.split
控制String.prototype.split()
的分割逻辑。
const customSplitter = {
[Symbol.split](string) {
return string.toUpperCase().split('');
}
};
console.log('hello'.split(customSplitter)); // ["H", "E", "L", "L", "O"]
Symbol.unscopables
Symbol.unscopables
用于排除某些属性被with
语句绑定。在现代JavaScript中with
已不推荐使用,但该特性仍存在。
const myObject = {
foo: 1,
bar: 2,
[Symbol.unscopables]: {
foo: true // 排除foo属性
}
};
with (myObject) {
console.log(bar); // 2
console.log(foo); // ReferenceError: foo is not defined
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:Symbol的元编程能力
下一篇:迭代协议基本概念