什么是伪数组
伪数组又称为类数组,类似数组的对象
伪数组的特征
1.按索引方式储存数据
{
0: 'M',
1: 'N',
2: 'A'
}
2.伪数组是一个对象(Object),而真实的数组是一个数组(Array)。
// 用instanceof()方法进行判断
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
let arrList = ['拉拉', '迪西', '小波', '丁丁'];
console.log(arr instanceof Array); //false
console.log(arrList instanceof Array); //true
console.log(arr instanceof Object); //true
3.具有length属性
但是length属性是静态的(真数组的长度可变),不会随着成员的变化而改变
不具有数组的push(), forEach()等方法
var arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
arr.length; //3,
arr[1]; //'b'
arr.push('d'); //Uncaught TypeError: arrLike.push is not a function
arr.length; //3,
4.伪数组的原型链中并没有数组的原型
arr.__proto__ === Object.prototype; //true
arr instanceof Object; //true
arr instanceof Array; //false
// prototype 显性原型 它是函数(包括构造函数)独有的,每个函数在创建之后都有一个 prototype 属性,它是一个指针,指向函数的原型对象,这个对象包含了所有实例对象共享的属性和方法 注 通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。
// __proto__(隐式原型)是对象的一个内置属性,是JS内部使用寻找原型链的属性,也就是说,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着__proto__依次向上查找
// 注意:用chrome和FF都可以访问到对象的__proto__属性,IE不可以。所以我们建议避免使用__proto__,因为它存在兼容性问题。
// 二者关系:一个对象的隐式原型指向构造该对象的构造函数的原型
//prototype 的作用是用来实现基于原型的继承与属性的共享。
// __proto__ 的作用构成原型链,同样用于实现基于原型的继承. 是当访问一个对象的属性时,如果内部没有该属性,就会在它的 __proto__ 属性所指的那个父对象去找,父对象没有,再去父对象的父对象里找…,直到 null,即原型链
// 注 instanceof 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。左值一般是一个对象,右值一般是一个构造函数 用来判断左值是否是右值的实例
5.可以通过for in和for循环遍历.
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
for(var key in arr) {
console.log(key, arr[key]) // 0 M, 1 N, 2 A, length 3
}
常见的伪数组
1.function内arguments对象.
function test() {
console.log(arguments, '1111111111111') // 打印结果如下图
}
test("name", "age");
2.还有像调用getElementsByTagName, document.childNodes之类的,它们都返回的NodeList对象都属于伪数组,也称为类数组.
<div class="nameList">
<div class="name1">拉拉</div>
<div class="name2">迪西</div>
<div class="name3">小波</div>
<div class="name4">丁丁</div>
</div>
<script>
let nodeList = document.getElementsByTagName('div');
console.log(nodeList)
let childNodes = nodeList[0].childNodes;
console.log(childNodes)
})
</script>
3.jQuery中的$()方法获取到的全部是伪数组,本质都是html标签序列.
<div class="name1">拉拉</div>
<div class="name2">迪西</div>
<div class="name3">小波</div>
<div class="name4">丁丁</div>
<script>
$(document).ready(function() {
let dom1 = $('div');
console.log(dom1, '1111111111111111') // 打印结果如下图
})
</script>
4.自定义的伪数组,例如 let obj={0:‘a’,1:‘b’,length:2}
5.文件域的files属性是一个伪数组
<input type="file" id="fileList">
<script>
let fileNode = document.querySelector("#fileList")
fileNode.addEventListener('change', function() {
console.log(fileNode.files)
})
</script>
怎么判断为伪数组
- instanceof() 代码同伪数组特征
- Array.isArray()
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
let arrList = ['拉拉', '迪西', '小波', '丁丁'];
console.log(Array.isArray(arr), Array.isArray(arrList)); // false true
3.Array.prototype.isPrototypeOf(),用于测试一个对象是否存在于另一个对象的原型链上。
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
let arrList = ['拉拉', '迪西', '小波', '丁丁'];
console.log(Array.prototype.isPrototypeOf(arrList)); // true
console.log(Array.prototype.isPrototypeOf(arr)); // false
4.proto.constructor,判断对象隐式原型的构造函数
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
let arrList = ['拉拉', '迪西', '小波', '丁丁'];
console.log(arr.__proto__.constructor); //ƒ Object() { [native code] }
console.log(arrList.__proto__.constructor); //ƒ Array() { [native code] }
5.Object.prototype.toString.call()方法,传递要检查的对象作为第一个参数,
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
let arrList = ['拉拉', '迪西', '小波', '丁丁'];
console.log(Object.prototype.toString.call(arr)); //[object Object]
console.log(Object.prototype.toString.call(arrList)); //[object Array]
伪数组转化为真数组的方法
1声明一个空数组,遍历伪数组把它们添加到所声明的空数组中 (最原始的办法,不推荐)
let arr = {
0: 'M',
1: 'N',
2: 'A',
length: 3,
}
var arrList = []; // 声明的空数组
for (var i = 0; i < arr.length; i++) {
arrList.push(arr[i])
}
2.使用 Array.prototype.slice.call() 或 Array.prototype.slice.apply()
let arr = {
0: '拉拉',
1: '迪西',
2: '小波',
3: '丁丁',
length: 4,
}
var arrList1 = Array.prototype.slice.call(arr);
console.log(arrList1); // ['拉拉', '迪西', '小波', '丁丁']
var arrList2 = Array.prototype.slice.apply(arr);
console.log(arrList2); // ['拉拉', '迪西', '小波', '丁丁']
3.使用 [].slice.call(),了解一下 js 原型链可知,实际上上面第二小点中的方法和这种方法是一样的,但前者的效率相对更高。
var arrList3 = [].slice.call(arr);
console.log(arrList3); // ['拉拉', '迪西', '小波', '丁丁']
4.使用 ES6 中的扩展运算符
var arrList4= [...arr] // ['拉拉', '迪西', '小波', '丁丁'] 会报错,需要自己写迭代器
5.使用 ES6 中数组的新方法 Array.from()
Array.from() 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
var arrList5 = Array.from(arr);
console.log(arrList5); // ['拉拉', '迪西', '小波', '丁丁']
注意这个返回的数组中,不会保留索引值以外的其他额外属性。
6.比如jQuery中$()获取的DOM伪数组,里面的context属性在被此方法转化之后就不会保留。
使用原型继承( Lis.proto = Array.prototype )
<div class="nameList">
<div class="name1">拉拉</div>
<div class="name2">迪西</div>
<div class="name3">小波</div>
<div class="name4">丁丁</div>
</div>
<script>
var dom1 = document.querySelectorAll('div');
console.log(dom1.constructor === Array) // false
dom1.__proto__ = Array.prototype
console.log(dom1.constructor === Array) // false
</script>