什么是类数组
- 是一个普通对象,不具备数组自带丰富的内建方法, 写法上跟数组一样,但不是数组,原型是Object。
- key是以数字或者字符串数字组成
- 必须有length属性
- 字符串具有类数组得特性,但一般类数组特指对象
const arrayLike = {
0: "a",
1: "b",
2: "c",
name: "test",
length: 3
};
//由于类数组对象length属性声明了对象有多少个属性,所以可以使用for遍历对象属性:
for (let i = 0; i < arrayLike.length; i++) {
console.log(i + ":" + arrayLike[i]);
}
类数组和数组的区别
常见的类数组
arguments、NodeList、HTMLCollection、DOMTokenList等
function person(name, age, sex) {
console.log(arguments);
console.log( Object.prototype.toString.call(arguments))
}
person("name", "age", "sex");
const nodeList = document.querySelectorAll("box");
console.log("querySelectorAll type:", Object.prototype.toString.call(nodeList));
const htmlCollection = document.getElementsByTagName("div");
console.log("getElementsByTagName type:", Object.prototype.toString.call(htmlCollection));
const DOMTokenList = document.querySelector("div").classList;
console.log("classList:", DOMTokenList);
判断是否是类数组
function isArrayLikeObject(arr) {
// 不是对象直接返回
if (arr == null || typeof arr !== 'object') return false;
// 数值最大有效值
const lengthMaxValue = Math.pow(2, 53) - 1;
// 判断是否有length属性
if (!Object.prototype.hasOwnProperty.call(arr, "length")) return false;
// 判断length是否为数值类型
if (typeof arr.length !== 'number') return false;
// 判断length是否在正常得数值范围内
if (!isFiniter(arr.length)) return false;
// 判断构造函数是否是Array
if (Array === arr.constructor) return false;
// 长度有效得值
if (arr.length >= 0 && arr.length < lengthMaxValue){
return true;
} else {
return false;
}
}
console.log(isArrayLikeObject(null)); // false
console.log(isArrayLikeObject({ 0: "a", 1: "b", length: 2 })); // true
console.log(isArrayLikeObject({ 0: 1, 2: 3, length: "" })); // false
console.log(isArrayLikeObject({ 0: 1, 2: 3 })); // false
console.log(isArrayLikeObject([1, 2])); // false
类数组如何转换成数组
1、复制遍历
const arr = [];
const arrayLike = {
0: 1,
1: 2,
length: 2,
};
for (let i = 0; i < arrayLike.length; i++) {
arr[i] = arrayLike[i];
}
console.log(arr); // [1, 2]
2、slice、concat等
const arrayLike = {
0: 1,
1: 2,
length: 2,
};
const array1 = Array.prototype.slice.call(arrayLike);
console.log(array1); // [ 1, 2 ]
const array2 = Array.prototype.concat.apply([], arrayLike);
console.log(array2); // [ 1, 2 ]
3、Array.from
const arrayLike = {
0: 1,
1: 2,
length: 2,
};
console.log(Array.from(arrayLike)); // [ 1, 2 ]
4、Array.apply
const arrayLike = {
0: 1,
1: 2,
length: 2,
};
console.log(Array.apply(null, arrayLike)); // [ 1, 2 ]
5、扩展运算符
console.log([...document.body.childNodes]); // [div, script, script...]
// arguments
function argumentsTest() {
console.log([...arguments]); // [ 1, 2, 3 ]
}
argumentsTest(1, 2, 3);
如何让类数组使用上数组丰富的内建方法
在类数组对象上直接定义数组原型的方法
运用call或者apply显示绑定this的指向
例如我想通过 filter 方法过滤出类数组中元素包含 “i” 这个字符的所有元素。
const arrayLike = {
0: "i love",
1: "you",
length: 1,
};
console.log([].filter.call(arrayLike, (item) => item.includes("i"))); // [ 'i love' ]
为什么会这样?其实可以想想 filter 是如何实现的。
[].__proto__.myfilter = function (callback) {
let newArr = [];
for (let i = 0; i < this.length; i++) {
if (callback(this[i])) {
newArr.push(this[i]);
}
}
return newArr;
};
可以看出因为 filter 实现是通过 this 进行绑定的,哪个数组调用了这个filter,filter中的 this 就指向哪个数组