Symbol的11个内置符号的使用场景

以下是11 个内置 Symbol 及其典型使用场景或面试题。


1. Symbol.iterator

用途 :定义对象的默认迭代器,用于 for...of、扩展运算符 ... 等。

ts 复制代码
const myIterable = {
  [Symbol.iterator]() {
    let step = 0;
    return {
      next() {
        step++;
        if (step <= 3) return { value: step, done: false };
        return { done: true };
      }
    };
  }
};

for (const v of myIterable) {
  console.log(v); // 1, 2, 3
}

面试题

如何让 { a: 1, b: 2, c: 3 }这样的普通对象支持 for...of循环?

ts 复制代码
const obj = {
  a: 1,
  b: 2,
  c: 3,
  *[Symbol.iterator]() {
    yield* Object.values(this)[Symbol.iterator]();
  },
};

for (const val of obj) {
  console.log(val); // 输出: 1, 2, 3
}

如何实现一个无限递增数字的迭代器?

ts 复制代码
const infiniteCounter = {
  *[Symbol.iterator]() {
    let count = 0;
    while (true) {
      yield count++;
    }
  },
};

const iterator = infiniteCounter[Symbol.iterator]();
console.log(iterator.next().value); // 0
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
// ...无限递增

2. Symbol.asyncIterator(ES2018)

用途 :异步数据流(如分页API)​,用于 for await...of。

ts 复制代码
const asyncPager = {
  data: [1, 2, 3, 4, 5],
  pageSize: 2,
  currentPage: 0,
  async *[Symbol.asyncIterator]() {
    while (this.currentPage * this.pageSize < this.data.length) {
      const start = this.currentPage * this.pageSize;
      const end = start + this.pageSize;
      const chunk = this.data.slice(start, end);
      yield new Promise((resolve) => {
        setTimeout(() => resolve(chunk), 1000); // 模拟异步请求
      });
      this.currentPage++;
    }
  }
};

(async () => {
  for await (const page of asyncPager) {
    console.log(page); // [1, 2] (1秒后) → [3, 4] (1秒后) → [5] (1秒后)
  }
})();

3. Symbol.toStringTag

用途 :自定义 Object.prototype.toString.call(obj) 的输出。

ts 复制代码
class MyComponent {
  get [Symbol.toStringTag]() {
    return 'MyVueComponent';
  }
}

console.log(Object.prototype.toString.call(new MyComponent()));
// "[object MyVueComponent]"

应用场景:调试、日志、类型识别(如 Vue/React 组件标识)。


4. Symbol.hasInstance

用途 :自定义 instanceof 的行为。

ts 复制代码
class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

console.log([1, 2] instanceof MyArray); // true

面试题

实现一个 NegativeNumber类,使得任何负数都是它的实例。

ts 复制代码
class NegativeNumber {
  static [Symbol.hasInstance](instance) {
    return typeof instance === 'number' && instance < 0;
  }
}

console.log(-5 instanceof NegativeNumber); // true
console.log(5 instanceof NegativeNumber); // false

5. Symbol.isConcatSpreadable

用途 :控制数组 concat 时是否展开。

ts 复制代码
const arr1 = [1, 2];
const arr2 = [3, 4];
arr2[Symbol.isConcatSpreadable] = false;

console.log(arr1.concat(arr2)); // [1, 2, [3, 4]]

6. Symbol.species

用途 :指定派生类构造函数(如 map、filter 返回的实例类型)。

ts 复制代码
class MyArray extends Array {
  static get [Symbol.species]() {
    return Array; // map/filter 返回普通 Array 而非 MyArray
  }
}

const a = new MyArray(1, 2, 3);
console.log(a.map(x => x * 2) instanceof MyArray); // false

常见于:自定义集合类(如 Immutable.js、RxJS)。


7. Symbol.match

用途 :定义 String.prototype.match 调用时的行为。

ts 复制代码
const matcher = {
  [Symbol.match](str) {
    return str.includes('hello') ? ['hello'] : null;
  }
};

console.log('say hello'.match(matcher)); // ['hello']

8. Symbol.replace

用途 :定义 String.prototype.replace 的行为。

ts 复制代码
const replacer = {
  [Symbol.replace](str, substr) {
    return str.split(' ').join(substr);
  }
};

console.log('a b c'.replace(replacer, '-')); // "a-b-c"

9. Symbol.search

用途 :定义 String.prototype.search 的行为。

ts 复制代码
const searcher = {
  [Symbol.search](str) {
    return str.indexOf('world');
  }
};

console.log('hello world'.search(searcher)); // 6

10. Symbol.split

用途 :定义 String.prototype.split 的行为。

ts 复制代码
const splitter = {
  [Symbol.split](str) {
    return str.split(/[\s,]+/);
  }
};

console.log('a b,c'.split(splitter)); // ['a', 'b', 'c']

11. Symbol.unscopables

用途 :指定在 with 语句中被排除的属性(现代 JS 中极少使用)。

ts 复制代码
Array.prototype[Symbol.unscopables] = { copyWithin: true };

with ([]) {
  // copyWithin 不会被引入作用域
}

注意 :由于 with 已被严格模式禁用,此 Symbol 几乎无实际用途。

相关推荐
变与不变8061 小时前
js同步和异步难点重点详解
开发语言·javascript·ecmascript
Dovis(誓平步青云)1 小时前
多个链接不等于多份证据,新闻核验看板怎样合并来源
java·服务器·前端·javascript·人工智能·pdf·电脑
Dovis(誓平步青云)2 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
可乐鸡翅yeah_4 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
ss2735 小时前
AI全栈实战 | 2.3-01 组件库实战:Element Plus 怎么搭出专业界面,过度封装为什么成维护负担
前端·javascript·elementui·vue
福兮说5 小时前
URL 编码的七个坑:c++ 传到后端变空格、%25 套娃、截断 emoji 直接报错
开发语言·前端·javascript·node.js·url
小的时候可菜了5 小时前
JS 异步的本质:从单线程到 thenable(一条进化链)
开发语言·前端·javascript
可乐鸡翅yeah_5 小时前
hls.js 配置 loadStartPosition,点播起始播放位置踩坑
开发语言·javascript·网络协议·ecmascript·m3u8在线
web打印社区6 小时前
Windows 网页静默打印设置步骤:客户端、防火墙与联调清单
开发语言·前端·javascript·chrome·pdf·ecmascript
web打印社区6 小时前
JS 静默打印怎么做:纯前端为什么不行,以及最小可跑通写法
开发语言·前端·javascript·websocket·网络协议·http·pdf