一、简介:
伪数组:
- 是对象,不是数组( obj instanceof Array === false)
必须有length属性
,但如果这个对象的length不为0,那么必须要按照数组下标存储数据不能调用
push()、indexOf()等数组方法
为了方便大家理解,举几个例子:
// 不是伪数组
var obj = {};
var obj2 = { length: 3 };
var obj3 = { 'a':1 , length:1};
// 是伪数组
var obj4 = { length: 0 };
var obj5 = { 0: '888', length: 1 };
var obj6 = { 0: '1', 1:2 , length: 2 };
var obj7 = { 99: 'abc', length: 100 }
概括来说:
伪数组就是:是对象不是数组; 有length属性,有数组的索引特征,但没有数组的push()等方法。
典型的伪数组:
- 函数的arguments参数
- HTMLCollection对象、NodeList对象 (调用getElementsByTagName,document.childNodes之类的,它们返回的是NodeList对象)
- jQuery对象
伪数组与真数组:
要知道 数组是有length属性的,而对象没有
;因而为了让对象也有length属性,所以伪数组诞生了。
其实伪数组和真数组都是对象,也都有length属性,甚至连访问元素的方式(eg:arguments[2])都一样;但不同的是,伪数组不能像数组那样调用像push()、indexOf()之类的数组方法
。
怎么判断 是 伪数组 还是 真数组?
我们可以用instanceof、constructor、Object.prototype.toString.call(X)等来判断是否为伪数组。
二、调用数组方法
伪数组不能像数组那样调用像push()、indexOf()之类的方法,但我就是任性的想调用,怎么办?
既然无法直接调用,我们可以用 Function.call 间接调用:
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
console.log(Array.prototype.join.call(arrayLike, '&')); // 'name&age&sex'
console.log(Array.prototype.slice.call(arrayLike, 0));// ["name", "age", "sex"]
// slice可以做到类数组转数组
var a = Array.prototype.map.call(arrayLike, function(item){
return item.toUpperCase();
});
console.log(a);// ["NAME", "AGE", "SEX"]
三、伪数组转数组:
我们有四种方法,将伪数据转换为真正的Array对象:
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
// 1. slice
console.log(Array.prototype.slice.call(arrayLike)); // ["name", "age", "sex"]
// 2. splice
console.log(Array.prototype.splice.call(arrayLike, 0)); // ["name", "age", "sex"]
// 3. ES6 Array.from
console.log(Array.from(arrayLike)); // ["name", "age", "sex"]
// 4. apply
console.log(Array.prototype.concat.apply([], arrayLike));// ["name", "age", "sex"]
上面的四种方法,只有用splice的方法会改变伪数组,另外三种都会返回一个新数组。
拓展:
我们模拟一下Array.prototype.slice.call(likeArray)
的内部实现:
Array.prototype.slice = function(start,end){
var result = [];
start = start || 0;
end = end || this.length;
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
};