深入研究数组与伪数组

Posted fine1998_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入研究数组与伪数组相关的知识,希望对你有一定的参考价值。

目录

前言

一、伪数组的概念 

二、常见的伪数组 

1、函数中存储所有实参的arguments对象

 2、DOM提供的获取页面节点的方法

三、 数组与伪数组的区别

四、判断伪数组 

五、伪数组转为真数组 


前言

在学习数组方法后,对数组的理解更加深刻了。但是在javascript中存在伪数组的概念,那么伪数组是什么?与数组是什么关系?伪数组的“伪”体现在哪里呢?这篇文章就来学习一下伪数组吧!

一、伪数组的概念 

伪数组是一种按照索引存储数据且具有 length 属性的对象

具有以下特点:

1、可以使用索引对数据进行操作;

2、具有length(长度)属性;

3、但是不能使用数组的方法,如push,pop等数组方法

举个手写的伪数组例子: 

var arrayLike = 
  0: "x",
  1: "y",
  2: "z",
  length: 3,
;

二、常见的伪数组 

1、函数中存储所有实参的arguments对象

function fn() 
            console.dir(arguments);//[Arguments]  '0': 1, '1': 2, '2': 3, '3': 4 
        
fn(1,2,3,4);

 2、DOM提供的获取页面节点的方法

2.1document.querySelectorAll()获取到的NodeList 对象

var lis = document.querySelectorAll('li');
        console.log(lis);//NodeList(4) [li, li, li, li]
        lis.forEach(function (value) 
            console.log(value);//lis内所有元素
        )

注意:NodeList 对象是文档节点的集合,具有forEach方法,但不具有其他数组方法

2.2 document.getElementsByClassName()、getElementsByTagName()、node.children等等获取到的htmlCollection对象

var lis = document.getElementsByClassName('cat');
        console.log(lis);//HTMLCollection(4) [li.cat, li.cat, li.cat, li.cat]
        lis.forEach(function (value) 
            console.log(value);//Uncaught TypeError: lis.forEach is not a function
        )
var lis = document.getElementsByTagName('li');
        console.log(lis);//HTMLCollection(4) [li.cat, li.cat, li.cat, li.cat]
        lis.forEach(function (value) 
            console.log(value);//Uncaught TypeError: lis.forEach is not a function
        )

注意:HTMLCollection对象是文档元素节点的集合,不具有任何数组方法 

除此之外,还有很多常用的伪数组,就不一一列举。 

三、 数组与伪数组的区别

1、伪数组与数组都属于对象,但是伪数组是基于Object构造函数创建的,数组是基于Array构造函数创建的。构造函数的方法写在其原型对象prototype开辟的内存内,基于构造函数创建的对象会拥有其方法。Object构造函数属于最顶级对象,因此根据原型链,伪数组只能拥有Object.prototype 的属性值,不能拥有Array.prototype 的属性值,因此不具有数组的方法。

var obj = ;// 拥有Object.prototype的属性值
var arr = [];//同时拥有Array.prototype和Object.prototype的属性值

2、伪数组的长度作为对象的一个属性,不会随索引属性的改变而改变。 

四、判断伪数组 

1、instanceof()

 var arrayLike = 
                0: "x",
                1: "y",
                2: "z",
                length: 3,
            ;
var arr=[1,2,3,4];
console.log(arrayLike instanceof Array);//false
console.log(arr instanceof Array);//true

2、Array.isArray()

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr = [1, 2, 3, 4];
console.log(Array.isArray(arrayLike));//false
console.log(Array.isArray(arr));//true

3、《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

 4、Array.prototype.isPrototypeOf(),用于测试一个对象是否存在于另一个对象的原型链上。

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr = [1, 2, 3, 4];
console.log(Array.prototype.isPrototypeOf(arrayLike));  // false
console.log(Array.prototype.isPrototypeOf(arr));  // true

5、__proto__.constructor,判断对象隐式原型的构造函数 

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr = [1, 2, 3, 4];
console.log(arrayLike.__proto__.constructor);//ƒ Object()  [native code] 
console.log(arr.__proto__.constructor);//ƒ Array()  [native code] 

6、Object.prototype.toString.call()方法,传递要检查的对象作为第一个参数,称为 thisArg

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr = [1, 2, 3, 4];
console.log(Object.prototype.toString.call(arrayLike));  //[object Object] 
console.log(Object.prototype.toString.call(arr));   //[object Array]

五、伪数组转为真数组 

1、Array.from()

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr=Array.from(arrayLike);
console.log(Array.isArray(arr));//true

2、 slice()  

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr = [].slice.call(arrayLike);
console.log(Array.isArray(arr));//true

3、concat() 

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 3,
        ;
var arr = [].concat.apply([], arrayLike);
console.log(Array.isArray(arr));//true

4、利用for循环遍历 

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            length: 5,
        ;
        var arr = [];
        for (var i = 0; i < arrayLike.length; i++) 
            arr.push(arrayLike[i]);
        
        console.log(arr);// ['x', 'y', 'z']

5、扩展运算符

const el = [...document.querySelectorAll('p')];

console.log(el);// (3) [p, p, p]

注意:以上方法实现的原理都是通过拷贝伪数组,将其值添加到一个新数组中,完成真数组的转换,这些拷贝都是浅拷贝。如果伪数组中包含引用数据类型,新数组与伪数组对值的更改会互相影响。

6、封装函数,实现深拷贝伪数组 

var arrayLike = 
            0: "x",
            1: "y",
            2: "z",
            3: [100, 200],
            length: 4,
        ;
        var arr = [];
        // 封装函数 
        function deepCopy(newobj, oldobj) 
            for (var k in oldobj) 
                // 判断我们的属性值属于那种数据类型
                // 1. 获取属性值  oldobj[k]
                var item = oldobj[k];
                // 2. 判断这个值是否是数组
                if (item instanceof Array) 
                    newobj[k] = [];
                    deepCopy(newobj[k], item)//数组循环时,k为索引值,item为数组本身,newobj[0]='pink',newobj[1]=red;全部复制完后结束
                 else if (item instanceof Object) 
                    // 3. 判断这个值是否是对象
                    newobj[k] = ;
                    deepCopy(newobj[k], item)
                 else 
                    // 4. 属于简单数据类型
                    newobj[k] = item;//第一次循环:k='id',item=1,将新对象属性值=旧对象属性值,同时新对象也创建了新属性
                

            
        
        deepCopy(arr, arrayLike);
        console.log(arr);//['x', 'y', 'z', [100,200]]
        arr[3][0] = 1000;
        console.log(arr);// ['x', 'y', 'z', [1000,200]]
        console.log(arrayLike);//0: 'x', 1: 'y', 2: 'z', 3: [100,200], length: 4未改变伪数组中的值
        for (var i = 0; i < arr.length; i++) 
            console.log(arr[i]);//x y z [1000,200]
        

以上是关于深入研究数组与伪数组的主要内容,如果未能解决你的问题,请参考以下文章

真数组与伪数组

js中鉴别数组暨与伪数组的区别

jquery---调用静态方法-each--map-数组与伪数组的差别

cache缓存与伪共享

PHP内核深入研究 - 数组及其遍历顺序

安卓bitmap与字节数组关系深入研究应用