参考链接:带你手写一个对象,深入理解可迭代对象是什么,与类数组有什么区别
可迭代对象( iterable object)和类数组(array-like)
1、类数组对象
最常见的类数组对象,就是function的arguments
let a = function() {
console.log(arguments)
}
a(1, 2, 3)
有两种方式可以处理这种类数组对象
首先是可以通过Array.from将其变为数组
let args = Array.from(arguments)
另一种方式是通过 ...
解构参数的形式
let a = function (...args) {
console.log(args) // [1, 2, 3]
}
a(1, 2, 3)
2、可迭代对象
可迭代对象是数组的泛化。数组和字符串都是可迭代的
// 这里声明一个range对象,它代表一个数字区间
let range = {
from: 1,
to: 5
}
// 我们希望 for..of 这样运行:
// 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内的完整实现
let range = {
from: 1,
to: 5
};
// 1. for..of 调用首先会调用这个:
range[Symbol.iterator] = function() {
// ……它返回迭代器对象(iterator object):
// 2. 接下来,for..of 仅与此迭代器一起工作,要求它提供下一个值
return {
current: this.from,
last: this.to,
// 3. next() 在 for..of 的每一轮循环迭代中被调用
next() {
// 4. 它将会返回 {done:.., value :...} 格式的对象
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// 现在它可以运行了!
for (let num of range) {
alert(num); // 1, 2, 3, 4, 5
}
3、Array.from
上面两种对象,都可以用Array.from转为数组
let arrayLike = {
0: "Hello",
1: "World",
length: 2
};
let arr = Array.from(arrayLike); // (*)
alert(arr.pop()); // World(pop 方法有效)
// 假设 range 来自上文的例子中
let arr = Array.from(range);
alert(arr); // 1,2,3,4,5 (数组的 toString 转化方法生效)
语法
Array.from(arrayLike[, mapFn[, thisArg]])
可选的第二个参数 mapFn
可以是一个函数,该函数会在对象中的元素被添加到数组前,被应用于每个元素,此外 thisArg
允许我们为该函数设置 this
。
// 假设 range 来自上文例子中
// 求每个数的平方
let arr = Array.from(range, num => num * num);
alert(arr); // 1,4,9,16,25
4、总结
类数组对象必须有索引属性和length属性
可迭代对象必须实现Symbol.iterator方法