JS中类数组转数组的方法(ArrayLike)
1、首先我们要清楚什么是类数组(ArrayLike)
- 拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解)
- 不具有数组的所有方法
2、JavaScript中常见的类数组
- arguments对象
- DOM方法返回结果(getElementsByTagName()、getElementsByClassName()…)都是类数组
3、判断一个对象是否为类数组
function isArrayLike(obj) {
if (obj && // obj is not null, undefined, etc. =>obj不为空
typeof obj === 'object' && // obj is an object=>obj是一个对象
isFinite(obj.length) && // obj.length is a finite number=>obj的长度是一个有限数字
obj.length >= 0 && // obj.length is non-negative=>obj的长度是一个非负数字
obj.length===Math.floor(obj.length) && // obj.length is an integer=>obj的长度是一个正数
obj.length < 4294967296) // obj.length < 2^32=>obj的长度小于2^32幂
return true; // Then obj is array-like =>obj是一个类数组
else
return false; // Otherwise it is not =>obj不是一个类数组
}
4、如何确定这个对象是一个数组
- 第一种方式:通过constructor来判断他的所属类是不是Array。如果是那么他就是一个数组,反之不是
console.log(ary.constructor===Array);=> true
console.log(oLis.constructor===Array);=>false
- 第二种方式:通过instanceof方法,检测这个对象是否为Array的一个实例
console.log(ary instanceof Array);=>true是数组
console.log(oLis instanceof Array);=>false不是数组
- 第三种方式:通过Object.prototype.toString.call(),检测这个对象的数据类型是否是"[object Array]"
console.log(Object.prototype.toString.call(ary) === "[object Array]");=>true是数组
console.log(Object.prototype.toString.call(oLis) === "[object Array]");=>false不是数组
- 第四种方式:通过ES5中提供的方法isArray()
console.log(Array.isArray(ary));=>true是数组
console.log(Array.isArray(oLis));=>false不是数组
6、我们为什么要将类数组转化成数组呢?
因为类数组不具有数组的所有方法,我们将其转换成数组以后就可以调用shift,unshift,splice,slice,concat,reverse,sort…这些强大的方法,非常方便!
7、类数组转数组的方法(终于到了重点的部分)
- Array.prototype.slice.call(arrayLike)或者[].slice.call(arrayLike)
众所周知slice是数组才能调用的方法,但是我们通过call改变了slice中this的指向,让他指向当前的这个类数组(也就是说将类数组克隆),得到了一个和arrayLike外表一样的数组,达到了质变的过程。
这里需要注意的一点是能调用call的只能是方法,所以我们不能用[].call(arrayLike)的方式将类数组转换成数组
//slice的内部实现
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
顺便附上转数组的通用函数
var toArray = function(s){
try{
return Array.prototype.slice.call(s);
} catch(e){
var arr = [];
for(var i = 0,len = s.length; i < len; i++){
//arr.push(s[i]);
arr[i] = s[i]; //据说这样比push快
}
return arr;
}
- 也可以通过[…arrayLike]转换成数组
console.log(Object.prototype.toString.call([...arrayLike]))//=>[object Array]
- 中间类继承
arrayLike.__proto__ = Array.prototype
8、实现两个数组的拼接
- 数组拼接我们首先想到的方法就应该是concat(),你会发现concat()虽然能实现数组的拼接但是他不能改变原数组,我们还得用变量来接受concat()的返回值,很麻烦。
var ary = [1, 2, 3, 4];
var newAry = [5, 6, 7];
console.log(ary.concat(newAry));=>[1,2,3,4,5,6,7]
console.log(ary);=>[1,2,3,4]
- 所以我们用下面的这个方法就可以解决上面的问题了,我们不就是要实现数组的拼接嘛,我们换一种思路想一下,拼接,无非不就是向让newAry中的每一项添加到ary的后面嘛,但是我们不能用ary.push(newAry)这个方式(不要问为什么,机制如此),所以我们可以把newAry的拆开,添加到ary中。
var ary = [1, 2, 3, 4];
var newAry = [5, 6, 7];
console.log(ary.push.apply(ary, newAry));//=>7数组的长度
console.log(ary);//=>[1,2,3,4,5,6,7]