Skip to content

08. [...10]

试修改原型,实现以下效果:

js
console.log( [...10] )
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1
2

本题其实就是要在 Number 原型上实现一个扩展运算符,这样就能够实现 [...num],其中 num 为整数。

【原理分析】扩展运算符执行的原理是:

  • 首先看是否有实现可迭代协议规定的方法,也就是 [Symbol.iterator] 这个函数(方法)是否存在,若存在,则可以进行扩展;
  • 其次,ES2019 对于对象也实现了扩展运算符,但是一般对象并没有可迭代方法,这是ES 规范特殊的扩展运算符的实现。

也就是说,我们要在 Number 原型上定义 [Symbol.iterator] 可迭代方法。

【代码实现】

js
Number.prototype[Symbol.iterator] = function () {
  let index = 0
  const arr = Array.from({ length: +this }, (_, i) => i + 1)
  return {
    next: () => {
      if (index < arr.length) {
        return {
          value: arr[index++],
          done: false
        }
      }
      return {
        value: undefined,
        done: true
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

TIP

不熟悉迭代器的朋友可以前往 MDN 学习:迭代器与生成器

事实上,实现了整数的可迭代性后,整数也具有了可迭代类型的其他特性,比如 let/const ... of ...

js
for (const n of 5) {
  console.log(n)
}
// 打印 1、2、3、4、5
1
2
3
4

一般我们会用生成器和 yield 替代迭代器(实际上生成器是一种特殊的迭代器),简化代码。上述例子的另一个方案是:

js
Number.prototype[Symbol.iterator] = function* () {
  yield* Array.from({ length: +this }, (_, i) => ++i)
}

console.log([...10])
// [1, 2, 3, 4,  5, 6, 7, 8, 9, 10]
1
2
3
4
5
6