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

相关推荐
niusir14 小时前
React 状态管理的演进与最佳实践
前端·javascript·react.js
张愚歌14 小时前
快速上手Leaflet:轻松创建你的第一个交互地图
前端
唐某人丶14 小时前
教你如何用 JS 实现 Agent 系统(3)—— 借鉴 Cursor 的设计模式实现深度搜索
前端·人工智能·aigc
看到我请叫我铁锤14 小时前
vue3使用leaflet的时候高亮显示省市区
前端·javascript·vue.js
南囝coding14 小时前
Vercel 发布 AI Gateway 神器!可一键访问数百个模型,助力零门槛开发 AI 应用
前端·后端
AI大模型14 小时前
前端学 AI 不用愁!手把手教你用 LangGraph 实现 ReAct 智能体(附完整流程 + 代码)
前端·llm·agent
小红14 小时前
网络通信基石:从IP地址到子网划分的完整指南
前端·网络协议
一枚前端小能手15 小时前
🔥 前端储存这点事 - 5个存储方案让你的数据管理更优雅
前端·javascript
willlzq15 小时前
深入探索Swift的Subscript机制和最佳实践
前端
RockerLau15 小时前
micro-zoe子应用路由路径污染问题
前端