类数组又被成为“伪数组”,因为并不是真正的数组,只是类似于数组而已,类数组具有以下特点:
- 拥有 length 属性
- 可以使用下标方式访问
- 但不能调用数组的方法
常见的类数组有以下四种:
- 字符串(是类数组,但不是类数组对象,下面三种都是类数组对象)
- 函数的 arguments
- DOM 的 NodeList
- 一个函数也可以被看作是类数组对象,因为它含有 length 属性值,代表可接收的参数个数
常见的类数组转换为数组的方法:
1、通过 call 或 apply 调用数组的 slice 方法来实现转换
Array.prototype.slice.call(arrayLike); // (推荐)
Array.prototype.slice.apply(arrayLike);
// 或者
[].slice.call(arrayLike)
2、通过 call 调用数组的 splice 方法来实现转换(不推荐,会改变原数组)
Array.prototype.splice.call(arrayLike, 0);
3、通过 apply 调用数组的 concat 方法来实现转换(字符串不可以)
Array.prototype.concat.apply([], arrayLike);
4、通过 Array.from 方法来实现转换(ES6新增)
Array.from(arrayLike);
5、展开运算符(ES6新增)
[...arrayLike];
【注意】 扩展运算符背后调⽤的是遍历器接⼝( Symbol.iterator ),如果⼀个对象没有部署这个接⼝,就⽆法转换。比如:
let arrayLike = {0:42, 1:52, 2:63, length:3}
[...arrayLike] // 报错 TypeError: Invalid attempt to spread non-iterable instance.
附:为类数组部署 Iterator 接⼝
方式1:
let arrayLike = {
0:42,
1:52,
2:63,
length:3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
[...arrayLike] // [42, 52, 63]
⽅式2:
NodeList.prototype[Symbol.iterator]= Array.prototype[Symbol.iterator];
// 或者
NodeList.prototype[Symbol.iterator]=[][Symbol.iterator];
[...document.querySelectorAll('div')] // 正常执⾏
6、$.makeArray()(字符串不可以)
JQ 中的内置⽅法;对类数组的对象有效。
$.makeArray( arrayLike )
7、for···of
【注意】 该方式背后调⽤的也是遍历器接⼝( Symbol.iterator )。
let arrayLike = {
0:42,
1:52,
2:63,
length:3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
let array = [];
for (const arrayLikeElement of arrayLike) {
array.push(arrayLikeElement)
}
console.log(array) // [42, 52, 63]