参考链接:带你手写一个对象,深入理解可迭代对象是什么,与类数组有什么区别

可迭代对象( iterable object)和类数组(array-like)

1、类数组对象

最常见的类数组对象,就是function的arguments

  1. let a = function() {
  2. console.log(arguments)
  3. }
  4. a(1, 2, 3)

image.png
有两种方式可以处理这种类数组对象
首先是可以通过Array.from将其变为数组

  1. let args = Array.from(arguments)

另一种方式是通过 ... 解构参数的形式

  1. let a = function (...args) {
  2. console.log(args) // [1, 2, 3]
  3. }
  4. a(1, 2, 3)

2、可迭代对象

可迭代对象是数组的泛化。数组和字符串都是可迭代的

  1. // 这里声明一个range对象,它代表一个数字区间
  2. let range = {
  3. from: 1,
  4. to: 5
  5. }
  6. // 我们希望 for..of 这样运行:
  7. // for(let num of range) ... num=1,2,3,4,5

关键点: 为了让range对象可迭代,需要为对象添加一个名为 Symbol.iterator 方法(一个专门用于使对象可迭代的内置symbol)

  • for..of 循环启动时,它会调用这个方法(如果没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next 方法的对象。
  • 从此开始,for..of 仅适用于这个被返回的对象
  • for..of 循环希望取得下一个数值,它就调用这个对象的 next() 方法。
  • next() 方法返回的结果的格式必须是 {done: Boolean, value: any},当 done=true 时,表示迭代结束,否则 value 是下一个值。

这里是range内的完整实现

  1. let range = {
  2. from: 1,
  3. to: 5
  4. };
  5. // 1. for..of 调用首先会调用这个:
  6. range[Symbol.iterator] = function() {
  7. // ……它返回迭代器对象(iterator object):
  8. // 2. 接下来,for..of 仅与此迭代器一起工作,要求它提供下一个值
  9. return {
  10. current: this.from,
  11. last: this.to,
  12. // 3. next() 在 for..of 的每一轮循环迭代中被调用
  13. next() {
  14. // 4. 它将会返回 {done:.., value :...} 格式的对象
  15. if (this.current <= this.last) {
  16. return { done: false, value: this.current++ };
  17. } else {
  18. return { done: true };
  19. }
  20. }
  21. };
  22. };
  23. // 现在它可以运行了!
  24. for (let num of range) {
  25. alert(num); // 1, 2, 3, 4, 5
  26. }

3、Array.from

上面两种对象,都可以用Array.from转为数组

  1. let arrayLike = {
  2. 0: "Hello",
  3. 1: "World",
  4. length: 2
  5. };
  6. let arr = Array.from(arrayLike); // (*)
  7. alert(arr.pop()); // World(pop 方法有效)
  8. // 假设 range 来自上文的例子中
  9. let arr = Array.from(range);
  10. alert(arr); // 1,2,3,4,5 (数组的 toString 转化方法生效)

语法

  1. Array.from(arrayLike[, mapFn[, thisArg]])

可选的第二个参数 mapFn 可以是一个函数,该函数会在对象中的元素被添加到数组前,被应用于每个元素,此外 thisArg 允许我们为该函数设置 this

  1. // 假设 range 来自上文例子中
  2. // 求每个数的平方
  3. let arr = Array.from(range, num => num * num);
  4. alert(arr); // 1,4,9,16,25

4、总结

类数组对象必须有索引属性和length属性
可迭代对象必须实现Symbol.iterator方法