深入研究数组与伪数组
Posted fine1998_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入研究数组与伪数组相关的知识,希望对你有一定的参考价值。
目录
前言
在学习数组方法后,对数组的理解更加深刻了。但是在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]
以上是关于深入研究数组与伪数组的主要内容,如果未能解决你的问题,请参考以下文章