这篇文章将要告诉你:
- 什么是类数组对象
- 类数组对象是如何出现的
- 如何避免使用类数组对象的常见问题
- 将类数组对象转换为普通对象的方法
类数组对象
类数组(Array-like Object)对象是 javascript 中比较冷门的内容,如果不了解的话,会被坑到。
类数组对象 foo 有以下两个陷阱:
- 有 foo.length 属性,却没有 foo.push() 方法
- 和 for-in 一起使用会有坑
类数组对象的主要使用/产生场景有以下两种:
- 函数参数 arguments
- querySelectorAll 的结果
下面来分别说一下。
1. 类数组对象——函数参数arguments
1 | function a(){ |
执行结果是:
- [1, 2, “aa”, callee: function, Symbol(Symbol.iterator): function]
- 3
- function a(){……(整个函数,此处省略)
- [object Arguments]
从执行结果可以看出,arguments的长度是传入参数的个数,但它还包括callee这个属性,指向自身。callee可以用于递归,比如在a()内可以继续通过调用arguments.callee(3,4,5)
实现递归。
2. 类数组对象——querySelectorAll的结果
类数组对象应该使用var i = 0; i < a.length;i++
方式遍历,和for-in一起使用的时候就是个灾难啊。
下面我们来看一下灾难现场:我们有三个DOM:
1 | <p class="cls-p">第一段</p> |
然后我们使用querySelectorAll进行选择,使用for-in遍历:
1 | var doms = document.querySelectorAll('.cls-p'); |
for-in 的打印结果真是令人目瞪口呆:
原理是这样的,for-in 遍历的是元素的所有属性,包括原型链中的属性,所以会打印出keys, entries 这种原型链的属性。
1 | console.log( 'keys' in doms) // true,'keys' 是 doms的属性 |
在上面的代码中,我们用了hasOwnProperty()
,这个方法用于判断当前属性是否是对象的自有属性。
那么我们可以用hasOwnProperty()
来填平for-in
的坑么?这是可以的。
1 | for (var i in doms) { |
当然,最好的办法就是:
- 使用for循环来遍历类数组对象
- 使用for循环来遍历类数组对象
- 使用for循环来遍历类数组对象
将类数组对象转换为普通对象
文章前面提到过,类数组对象有 foo.length 属性,却没有 foo.push() 方法。通过将类数组对象转换为普通对象,可以使用push()方法。
方法一:for 循环复制到新对象中
1 | function objToArr() { |
方法二:使用Array.prototype.slice方法
原理:slice() 不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。1
2
3
4
5
6
7
8
9
10function objToArr() {
// arguments.push[4];
// 如果运行上面的代码,会报错 "Uncaught TypeError: Cannot read property '4' of undefined"
var arr = Array.prototype.slice.call(arguments);
return arr;
}
var arr = objToArr(1, 2, 3);
arr.push(4);
console.log(arr); // [1,2,3,4],符合预期
参考文章: