欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript 之 类数组(伪数组)

程序员文章站 2022-06-10 08:34:41
...

伪数组对象

一、类(伪)数组对象

  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
    

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

相关标签: 类(伪)数组