Symbol符号是“唯一性”的类型

在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.matchString.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.replaceString.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.searchString.prototype.search调用,返回匹配项的索引。

ts 复制代码
class FirstVowel {
  [Symbol.search](str) {
    return str.search(/[aeiou]/);
  }
}

console.log("hello".search(new FirstVowel())); // 1 (e 的位置)

7.symbol.splitstring.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语句的作用域绑定

相关推荐
大圣编程1 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang1 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆2 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜3 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞4 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农6 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_943782357 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq7 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net
吠品7 小时前
LangChain 里 tool_call_id 为空?一次 MCP 工具集成的排查记录
前端