1、Array.isArray
基本使用
const arr = ["1"];
console.log("isArray:", Array.isArray(arr)); // true
非基本使用:
const arr = ["1"];
const proxy = new Proxy(arr, {});
console.log(proxy); // Proxy {0: '1'}
console.log("isArray:", Array.isArray(proxy)); // true
为什么上面 Array.isArray 判断代理对象是否数组返回 true 呢?
我们可以下面看看打印得到的状态
const arr = ["1"];
const proxy = new Proxy(arr, {});
console.log("__proto__:", proxy.__proto__ === Array.prototype); // __proto__: true
console.log("instanceof:", proxy instanceof Array); // instanceof: true
console.log("Proxy toString:", Object.prototype.toString.call(Proxy)); // Proxy toString: [object Function]
console.log("proxy toString:", Object.prototype.toString.call(proxy)); // proxy toString: [object Array]
console.log("Proxy.prototype:", Proxy.prototype); // Proxy.prototype: undefined
console.log("proxy instanceof Proxy:", proxy instanceof Proxy); // 报错
实际Array.isArray判断的是Proxy里面的target属性

如果使用的语法不支持Array.isArray,我们可以手写一个isArray的方法: Object.prototype.toString
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
}
const arr = ["1"];
const proxy = new Proxy(arr, {});
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(proxy)); // true
instanceof 可以正确判断对象的类型,其内部运行原理是:判断其原型链中是否能找到该类型的原型
注意instanceof 只能正确判断引用类型数据,而不能判断基本类型。 instanceof可以用来测试一个对象在其原型链上是否存在一个构造函数的prototype属性。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
根据instanceof的原理,可以使用instanceof来手写Array.isArray方法
Array.isArray = function (obj) {
if (typeof obj !== "object" || obj === null) {
return false;
}
return obj instanceof Array;
};
const arr = ["1"];
const proxy = new Proxy(arr, {});
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(proxy)); // true
Array.from
有三个参数
- arrayLike:类数组对象或者可遍历对象(Map、Set)等
- mapFn:可选参数,在最后生成数组后执行一次map方法后返回
- thisArg:可选参数,实际是Array.from(obj).map(mapFn, thisArg)
console.log("Array.from1:", Array.from({})); // Array.from1: []
console.log("Array.from2:", Array.from("")); // Array.from2: []
console.log("Array.from3:", Array.from({ a: 1, length: "10" }));
// Array.from3: (10) [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
console.log("Array.from4:", Array.from({ a: 1, length: "ss" })); // Array.from4: []
console.log("Array.from5:", Array.from([NaN, null, undefined, 0])); // Array.from5: (4) [NaN, null, undefined, 0]
根据之前文章《数组高级用法》里面写的类数组特征,可以做如下处理:
// 最大的整数
let maxSafeInteger = Math.pow(2, 32) - 1;
// 获取合法有效的整数
let ToInterOrInfinity = function(value) {
let number = Number(value);
if (isNaN(number)) return 0;
if (number === 0 || !isFinite(number)) return number;
return (number > 0 ? 1 : -1) *Math.floor(Math.abs(bumber));
}
// 获取长度
let ToLength = function (value) {
let len = ToInterOrInfinity (value);
return Math.min(Math.max(len, 0), maxSafeInteger);
}
let isCallable = function(fn) {
return typeof fn === 'function' || Object.toString.call(fn) === '[object Function]'
}
Array.from = function(arrayLink, mapFn, thisArg) {
let C = this;
//判断对象是否为空
if (arrayLike == null) {
throw new TypeError("Array.from requires an array-like object - not null or undefined");
}
//检查mapFn是否是方法
if (typeof mapFn !== "function" && typeof mapFn !== "undefined") {
throw new TypeError(mapFn + "is not a function");
}
let items = Object(arrayLike);
//判断 length 为数字,并且在有效范围内。
let len = ToLength(items.length);
if (len <= 0) return [];
let A = isCallable(C) ? Object(new C(len)) : new Array(len);
for (let i = 0; i < len; i++) {
let value = items[i];
if (mapFn) {
A[i] = typeof thisArg === "undefined" ? mapFn(value, i) : mapFn.call(thisArg, value, i);
} else {
A[i] = value;
}
}
return A;
}
Array.entries、Array.prototype.entries
- 作用:返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对
const arr = ["a", "b", "c"];
const iter = arr.entries();
console.log("iter:", iter); // iter: Array Iterator {}
// next函数访问
console.log("iter.next():", iter.next());
console.log("iter.next():", iter.next());
console.log("iter.next():", iter.next());
console.log("iter.next():", iter.next());
// for of迭代
for (let [k, v] of arr.entries()) {
console.log(k, v);
}

done 表示遍历是否结束,value 返回当前遍历的值
自己来实现下这个方法:
Array.prototype.entries = function () {
// 转换对象(引用数据类型返回自身)
const O = Object(this);
let index = 0;
const length = O.length;
return {
next() {
if (index < length) {
return { value: [index, O[index++]], done: false };
}
return { value: undefined, done: true };
},
};
}
上面手写的方法无法使用for of 不能正常执行,我们需要添加Symbol.iterator方法返回next即可实现
Array.prototype.entries = function () {
const O = Object(this);
let index = 0;
const length = O.length;
function next() {
if (index < length) {
return { value: [index, O[index++]], done: false };
}
return { value: undefined, done: true };
}
return {
next,
[Symbol.iterator]() {
return {
next,
};
},
};
}
数组还有 Array.prototype.keys,Array.prototype.keys,如果我们像上面这样写等于每个方法里面都要实现[Symbol.iterator],我们可以抽离其逻辑,代码如下:
Array.prototype[Symbol.iterator] = function () {
const O = Object(this);
let index = 0;
const length = O.length;
function next() {
if (index < length) {
return { value: O[index++], done: false };
}
return { value: undefined, done: true };
}
return {
next,
};
};
Array.prototype.entries = function () {
const O = Object(this);
const length = O.length;
let entries = [];
for (let i = 0; i < length; i++) {
entries.push([i, O[i]]);
}
const itr = this[Symbol.iterator].bind(entries)();
return {
next: itr.next,
[Symbol.iterator]() {
return itr;
},
};
};
Array.prototype.keys = function () {
const O = Object(this);
const length = O.length;
let keys = [];
for (let i = 0; i < length; i++) {
keys.push([i]);
}
const itr = this[Symbol.iterator].bind(keys)();
return {
next: itr.next,
[Symbol.iterator]() {
return itr;
},
};
};
Array.prototype.values = function () {
const O = Object(this);
const length = O.length;
let keys = [];
for (let i = 0; i < length; i++) {
keys.push([O[i]]);
}
const itr = this[Symbol.iterator].bind(keys)();
return {
next: itr.next,
[Symbol.iterator]() {
return itr;
},
};
};
Array.prototype.includes
- 判断数组是否含有某值,可判断NaN
const arr = [1, 2, 3, { a: 1 }, null, undefined, NaN, ""];
console.log("includes null:", arr.includes(null)); // includes null: true
console.log("indexOf null:", arr.indexOf(null)); // indexOf null: 4
console.log("includes NaN:", arr.includes(NaN)); // includes NaN: true
console.log("indexOf NaN:", arr.indexOf(NaN)); // indexOf NaN: -1
手写该方法
Number.isNaN = function (param) {
if (typeof param === "number") {
return isNaN(param);
}
return false;
};
Array.prototype.includes = function (item, fromIndex) {
// call, apply调用,严格模式
if (this == null) {
throw new TypeError("无效的this");
}
let O = Object(this);
let len = O.length >> 0;
if (len <= 0) {
return false;
}
const isNAN = Number.isNaN(item);
for (let i = 0; i < len; i++) {
if (O[i] === item) {
return true;
} else if (isNAN && Number.isNaN(O[i])) {
return true;
}
}
return false;
};
本文围绕ES6中数组的相关方法展开。介绍了Array.isArray的基本与非基本使用,还给出了手写实现方法;阐述了Array.from的三个参数;讲解了Array.entries等方法的作用及手写实现;最后介绍了Array.prototype.includes判断数组元素的功能及手写方法。

1万+

被折叠的 条评论
为什么被折叠?



