JavaScript 之 类数组(伪数组)
程序员文章站
2022-06-10 08:34:41
...
伪数组对象
一、类(伪)数组对象
- 类(伪)数组定义:
- 具有length属性
- 按索引方式存储数据
- 没有数组中方法
var fakeArray = {
length: 3,
"0": "first",
"1": "second",
"2": "third"
};
for (var i = 0; i < fakeArray.length; i++) {
console.log(fakeArray[i]);
}
Array.prototype.join.call(fakeArray,'+');
- 常见的类(伪)数组
- function内的arguments对象(定义一个函数,如果不知道用户传入几个参数,没办法计算时,arguments 可以获取传入的每个参数的值)
- DOM 对象列表(比如通过 document.getElementsByTags 、getElementsByTagName()、document.childNodes之类的返回的Nodelist对象得到的列表)
- jQuery 对象(比如 $(“div”))。
- 判断是否是类(伪数组)
《javascript权威指南》上给出了代码用来判断一个对象是否属于“类数组”。如下:
不过有个更简单的办法来判断,用 Array.isArrayfunction isArrayLike(o) { if (o && // o is not null, undefined, etc. typeof o === 'object' && // o is an object isFinite(o.length) && // o.length is a finite number o.length >= 0 && // o.length is non-negative o.length===Math.floor(o.length) && // o.length is an integer o.length < 4294967296) // o.length < 2^32 return true; // Then o is array-like else return false; // Otherwise it is not }
是类(伪)数组时为falseArray.isArray(fakeArray) //false; Array.isArray(arr) //true;
二、伪数组和数组的区别
- 伪数组是一个 Object,而真实的数组是一个 Array
fakeArray instanceof Array //false Object.prototype.toString.call(fakeArray) // [object Object] var arr = [1,2,3,4,6]; arr instanceof Array // true; Object.prototype.toString.call(arr) //[object Array]
- 从外观上看伪数组,看不出来它与数组的区别,在JavaScript内置对象中常见的伪数组就是大名鼎鼎的arguments:
(function() { console.log(typeof arguments); // 输出 object,它并不是一个数组 }());
- 另外在DOM对象中,childNodes也是伪数组
console.log(typeof document.body.childNodes); // 输出 object
三、类(伪)数组转变成数组的办法
伪数组存在的意义,是可以让普通的对象也能正常使用数组的很多方法
- 为什么伪数组就不能使用数组方法,为什么数组就能使用push方法
一个数组都是由她的构造器实例化出来的,var a = [];这是js的语法糖;
正规的用法:var a = new Array()
因为Array是一个构造函数,每一个构造函数都有原型,且构造函数构造出来的实例可以使用原型上的方法,也就是说因为Array的原型上有一些方法,所以每一个数组都可以使用push等方法
因为伪数组的构造器不是Array,当然不能使用Array原型上的push方法
-
通过call改变数组slice方法里的this指向
数组有一个方法slice,这个方法每次都会返回一个新数组,如果不传参的话,返回的新数组的元素和原数组的元素是一模一样的
如果伪元素也能执行这个方法的话,那么是不是就返回一个真正的数组,并且元素一样,但是不能直接执行
所以我们使用偷梁换柱的方法,让一个真正的数组,或者直接从Array.prototype上执行slice方法,但是在执行的时候通过call来将里面的this换成伪数组,这样的话,就会返回一个元素和伪数组元素一样的真正数组了
var arr = Array.prototype.slice.call(arguments)
//或Array.prototype.slice.call(arguments, [0, arguments.length])
////没有length的对象
var a={length:2, 0:'first', 1:'second'};
Array.prototype.slice.call(a);// ["first", "second"]
var a={length:2, 0:'first', 1:'second'};
Array.prototype.slice.call(a,1);// ["second"]
var a={0:'first', 1:'second'};
Array.prototype.slice.call(a,1);// []
var arr = Array.prototype.slice.call(arguments, 0); // 将arguments对象转换成一个真正的数组
Array.prototype.forEach.call(arguments, function(v) {
// 循环arguments对象
});
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]; //console.timeEnd测试以后比push快
}
return arr;
}
}
-
Array.from( )
Array.from()是ES6中新增的方法,可以将 两类对象 转为真正的数组:类数组对象和可遍历(iterable)对象(包括ES6新增的数据结构Set和Map)。
var arrayLike = {
'0':'a',
'1':'b',
'2':'c',
length:3
};
var arr = Array.from(arrayLike);//['a','b','c']
//把NodeList对象转换为数组,然后使用数组的forEach方法
var ps = document.querySelectorAll('p');
Array.from(ps).forEach(p){
console.log(p);
});
//转换arguments对象为数组
function foo(){
var args = Array.from(arguments);
//...
}
//只要是部署了Iterator接口的数据结构,Array.from都能将其转换为数组
Array.from('hello'); //['h','e','l','l','o'] 不是很懂Iterator
-
扩展运算符(…)
同样是ES6中新增的内容,扩展运算符(…)也可以将某些数据结构转为数组//arguments对象的转换 var args = [...arguments]; console.log(args instanceof Array) //true //NodeList对象的转换 console.log([...$('div')] instanceof Array) //true
【拓展】对象转换为数组
- for-in 语句
var arr2 = [] var object = { name:"xiaoming", age:"20", sayhi:function(){ console.log("hh") } } for (var i in object) { arr2.push(object[i]); //属性 //arr2.push(fakeArray[i]); //值 } console.log(arr2); //["xiaoming", "20", ƒ] console.log(arr2 instanceof Array) //true
好啦,写完我的第一篇学习文章啦,欢迎大家进行讨论。
上一篇: HTML5 Web存储
下一篇: 详解Angular动态组件