想成为那种不声不响,但是什么都做得很好的人。
对象与数组的关系
在JavaScript中,除了5种原始数据类型之外,其他所有的都是对象,包括函数(Function)。
JavaScript 的原型继承:
所有 JavaScript 的内置构造函数都是继承自 Object.prototype 。在这个前提下,可以理解为使用 new Array() 或 [] 创建出来的数组对象,都会拥有 Object.prototype 的属性值。
let obj = {};// 拥有 Object.prototype 的属性值
let arr = [];
//使用数组直接量创建的数组,由于 Array.prototype 的属性继承自 Object.prototype,
//那么,它将同时拥有 Array.prototype 和 Object.prototype 的属性值
结论: 对象没有数组 Array.prototype 的属性值
数组
定义: 数组是一种类列表对象,它的原型中提供了遍历和修改元素的相关操作。JavaScript 数组的长度和元素类型都是非固定的。只能用整数作为数组元素的索引,而不能用字符串。对象是没有索引的,是数组的基本特征。
var obj = {};
var arr = [];
obj[2] = 'a';
arr[2] = 'a';
console.log(obj[2]); // => a
console.log(arr[2]); // => a
console.log(obj.length); // => undefined
console.log(arr.length); // => 3
- obj[2]输出’a’,是因为对象就是普通的键值对存取数据
- 而arr[2]输出’a’ 则不同,数组是通过索引来存取数据,arr[2]之所以输出’a’,是因为数组arr索引2的位置已经存储了数据
- obj.length并不具有数组的特性,并且obj没有保存属性length,那么自然就会输出undefined
- 而对于数组来说,length是数组的一个内置属性,数组会根据索引长度来更改length的值
- 为什么arr.length输出3,而不是1
- 在给数组添加元素时,并没有按照连续的索引添加,所以导致数组的索引不连续,那么就导致索引长度大于元素个数
伪数组
定义:
- 伪数组是一个对象(Object),而真实的数组是一个数组(Array)
- 拥有length属性,且必须是number类型,其它属性(索引)为字符串
- 不具有数组所具有的方法,forEach()等,不过有Object的方法
- 伪数组长度不可变,真数组长度可以变
- 可以通过for in遍历
var fakeArray = {
length: 3,
"0": "first",
"1": "second",
"2": "third"
}
var arr = [1, 2, 3, 4]
// 真数组的方法来自Array.prototype
console.log(fakeArray instanceof Array) //false
console.log(arr instanceof Array) // true
Array.isArray(fakeArray) // false;
Array.isArray(arr) // true;
console.log(arr.__proto__ === Array.prototype) // true
console.log(fakeArray.__proto__ === Array.prototype) // false
console.log(fakeArray.__proto__ === Object.prototype) // true
arr.forEach(x => console.log(x)) // 1 2 3 4
fakeArray.forEach(x => console.log(x)) // fakeArray.forEach is not a function
Object.keys(fakeArray) // ["0", "1", "2", "length"]
常见的伪数组有:
- 函数内部的 arguments
- DOM 对象列表(比如通过 document.getElementsByTags 得到的列表)
- jQuery 对象(比如 $("div") )
伪数组是一个 Object,而真实的数组是一个 Array。
伪数组存在的意义,是可以让普通的对象也能正常使用数组的很多方法,比如:
- 使用Array.prototype.slice.call();
var arr = Array.prototype.slice.call(arguments);
Array.prototype.forEach.call(arguments, function(v) {
// 循环arguments对象
});
// push
// some
// every
// filter
// map
// ...
- 使用[].slice.call()
var fakeArray = {
length: 3,
"0": "first",
"1": "second",
"2": "third"
}
var arr = [].slice.call(fakeArray)
console.log(arr) // ["first", "second", "third"]
- 使用ES6中的Array.from方法
var fakeArray = {
length: 3,
"0": "first",
"1": "second",
"2": "third"
}
var arr = Array.from(fakeArray)
console.log(arr) // ["first", "second", "third"]
- 使用扩展运算符,也是ES6的语法
var fakeArray = document.querySelectorAll('div')
var newArr= [...fakeArray]
console.log(newArr.__proto__ === Array.prototype) // true
伪数组转换为真数组原理
Array.prototype.slice = function (start, end) {
start = start || 0
end = start || this.length
const arr = []
for (var i = start; i < end; i++) {
arr.push(this[i])
}
return arr
}
结论
- 对象没有数组 Array.prototype 的属性值,类型是 Object ,而数组类型是 Array
- 数组是基于索引的实现, length 会自动更新,而对象是键值对
- 使用对象可以创建伪数组,伪数组可以正常使用数组的大部分方法
网友评论