在TypeScript中,Symbol是一种特殊的、不可变的数据类型,它的主要用途是创建唯一的标识符。
它在ES6中引入的js原始类型,ts也完全支持。
1.Symbol的基本用法(创建唯一的Symbol
)
使用Symbol()函数来创建一个Symbol。
每次创建都是唯一的
ts
const sym1 = Symbol();
const sym2 = Symbol();
console.log(sym1 === sym2); // false,每个 Symbol 都是唯一的
2.Symbol的常见用途
用作对象属性时,防止冲突
ts
name: "Alice",
[Symbol("id")]: 123,
[Symbol("id")]: 456 // 不会覆盖!这是另一个唯一的 Symbol
};
console.log(User)

3.可选的描述,但不影响唯一性
ts
Symbol("key") !== Symbol("key"); // true,它们仍是不同的
4.全局Symbol注册表(Symbol.for)-唯一性的可控例外
ts
const s1 = Symbol.for("shared"); // 注册或获取全局 Symbol
const s2 = Symbol.for("shared");
console.log(s1 === s2); // true
ts
const 我的爱 = Symbol("forever");
const 你的爱 = Symbol("forever");
console.log(我的爱 === 你的爱); // false
// 因为每一份爱都是唯一的
// 但我们可以约定:
const 我们的爱 = Symbol.for("us"); // 全局唯一,属于我们两个人
console.log("尽管爱是唯一的,但我们选择了彼此,成为唯一的我们。");
ts
// 第一次调用:创建并注册
const sym1 = Symbol.for("com.myapp.userCache");
console.log("第一次创建:", sym1); // Symbol(com.myapp.userCache)
// 第二次调用:从注册表中获取已存在的 Symbol
const sym2 = Symbol.for("com.myapp.userCache");
console.log("第二次获取:", sym2); // Symbol(com.myapp.userCache)
// 它们是完全相同的!
console.log(sym1 === sym2); // true
内置symbols用来表达语言内部的行为:
1.Symbol.hasInstance
方法被instanceof
调用,用于判断一个对象是否是某个构造器的实例。
ts
class ArrayLike {
static [Symbol.hasInstance](obj) {
return Array.isArray(obj) && obj.length > 0;
}
}
console.log([1, 2, 3] instanceof ArrayLike); // true
console.log([] instanceof ArrayLike); // false (空数组)
console.log("not array" instanceof ArrayLike); // false
2.symbol.isConcatSpreadale
布尔值,控制Array.prototype.concat
是都"展开"该对象的元素。
ts
const arr1 = [1, 2];
const arr2 = [3, 4];
// 默认行为:展开
console.log(arr1.concat(arr2)); // [1, 2, 3, 4]
// 自定义:不展开
const notSpreadable = {
[Symbol.isConcatSpreadable]: false,
0: 'a',
1: 'b',
length: 2
};
console.log(arr1.concat(notSpreadable)); // [1, 2, {0: 'a', 1: 'b', length: 2}]

3.symbol.iterator
返回对象的默认迭代器,用于for...of、扩展运算
符等。
ts
const myRange = {
from: 1,
to: 5,
[Symbol.iterator]() {
let current = this.from;
const end = this.to;
return {
next() {
if (current <= end) {
return { done: false, value: current++ };
} else {
return { done: true };
}
}
};
}
};
for (const n of myRange) {
console.log(n); // 1, 2, 3, 4, 5
}

4.symbol.match
被String.prototype.match
调用,自定义字符串匹配行为。
ts
class CustomMatcher {
[Symbol.match](str) {
return str.includes("hello") ? ["Hello Found!"] : null;
}
}
console.log("say hello world".match(new CustomMatcher()));
// ["Hello Found!"]

5.symbol.replace
被String.prototype.replace
调用,自定义替换逻辑。
ts
class VowelReplacer {
[Symbol.replace](str, newChar = '*') {
return str.replace(/[aeiou]/g, newChar);
}
}
console.log("hello".replace(new VowelReplacer(), '#'));
// "h#ll#"

6.symbol.search
被String.prototype.search
调用,返回匹配项的索引。
ts
class FirstVowel {
[Symbol.search](str) {
return str.search(/[aeiou]/);
}
}
console.log("hello".search(new FirstVowel())); // 1 (e 的位置)
7.symbol.split
被string.prototype.split
调用,自定义分割逻辑。
ts
class SplitOnVowels {
[Symbol.split](str) {
return str.split(/[aeiou]/);
}
}
console.log("hello".split(new SplitOnVowels()));
// ["h", "ll", ""]

8.symbol.species
控制派生对象的构造器。例如map()、filter()返回什么类型。
ts
class MyArray extends Array {
static get [Symbol.species]() {
return Array; // 让 map 返回普通数组,而不是 MyArray
}
}
const arr = new MyArray(1, 2, 3);
const mapped = arr.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
9.symbol.toprimitive
控制对象转原始值(string、number、default)的行为。
ts
const money = {
amount: 100,
currency: "USD",
[Symbol.toPrimitive](hint) {
if (hint === "string") {
return `${this.currency}${this.amount}`;
} else if (hint === "number") {
return this.amount;
} else {
return this.amount; // default
}
}
};
console.log(String(money)); // "USD100"
console.log(Number(money)); // 100
console.log(money + 50); // 150 (number context)

10.symbol.toStringTag
自定义object.prototype.toString
的返回标签。
ts
const myPet = {
name: "Buddy",
[Symbol.toStringTag]: "Dog",
};
console.log(Object.prototype.toString.call(myPet));
// "[object Dog]"
// 常用于自定义类
class ApiResponse {
get [Symbol.toStringTag]() {
return "ApiResponse";
}
}
console.log(new ApiResponse()); // [object ApiResponse]

11.symbol.unscopables
指定哪些属性在with语句中不应被绑定。
ts
// Array 默认的 unscopables
Array.prototype[Symbol.unscopables] = {
...Array.prototype[Symbol.unscopables],
keys: true, // 表示 'keys' 不应被 with 绑定
values: true
};
// 演示
const obj = { keys: "custom keys value" };
with (["a", "b"]) {
console.log(keys); // 仍然输出 "custom keys value",而不是数组的 keys() 方法
// 因为 keys 被标记为 unscopables,不会从数组"泄漏"到作用域

补充:synbol.asyncIterator
重要的内置symbol,用于异步迭代。
ts
const asyncStream = {
[Symbol.asyncIterator]() {
const values = [1, 2, 3];
let i = 0;
return {
async next() {
await new Promise(r => setTimeout(r, 100)); // 模拟异步
return i < values.length
? { value: values[i++], done: false }
: { done: true };
}
};
}
};
// 必须在 async 函数中使用
(async () => {
for await (const x of asyncStream) {
console.log(x); // 1, 2, 3(每100ms输出一个)
}
})();

总结:
1.hasInstance
自定义instantceof
判断逻辑
2.isConcatSpreadable
控制数组拼接是否展开
3.iterator/asyncIterator
使对象可迭代(同步/异步)
4.match/replace/search/split
自定义正义行为
5.species
控制派生对象类型(如map()返回类型)
6.toPrimitive
字典贵toString()标签
7.unscopables
控制with语句的作用域绑定