JavaScript 之 类数组(伪数组)

伪数组对象

一、类(伪)数组对象

  1. 类(伪)数组定义:
    • 具有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,'+');
  1. 常见的类(伪)数组
    • function内的arguments对象(定义一个函数,如果不知道用户传入几个参数,没办法计算时,arguments 可以获取传入的每个参数的值)
    • DOM 对象列表(比如通过 document.getElementsByTags 、getElementsByTagName()、document.childNodes之类的返回的Nodelist对象得到的列表)
    • jQuery 对象(比如 $(“div”))。
  2. 判断是否是类(伪数组)
    《javascript权威指南》上给出了代码用来判断一个对象是否属于“类数组”。如下:
    function 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
    }
    
    不过有个更简单的办法来判断,用 Array.isArray
    是类(伪)数组时为false
    Array.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
    

三、类(伪)数组转变成数组的办法

伪数组存在的意义,是可以让普通的对象也能正常使用数组的很多方法

  1. 为什么伪数组就不能使用数组方法,为什么数组就能使用push方法
    一个数组都是由她的构造器实例化出来的,var a = [];这是js的语法糖;
    正规的用法:var a = new Array()
    因为Array是一个构造函数,每一个构造函数都有原型,且构造函数构造出来的实例可以使用原型上的方法,也就是说因为Array的原型上有一些方法,所以每一个数组都可以使用push等方法
    因为伪数组的构造器不是Array,当然不能使用Array原型上的push方法
  2. 通过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;
    }
}
  1. 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
  1. 扩展运算符(…)
    同样是ES6中新增的内容,扩展运算符(…)也可以将某些数据结构转为数组
    //arguments对象的转换
    var args = [...arguments];
    console.log(args instanceof Array)	//true
    //NodeList对象的转换
    console.log([...$('div')] instanceof Array)	//true
    

【拓展】对象转换为数组

  1. 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
    

好啦,写完我的第一篇学习文章啦,欢迎大家进行讨论。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值