实现Array.isArray方法
手写实现判断一个值是否为数组的Array.isArray方法,掌握类型检测的原理
问题
Array.isArray() 是 ES5 引入的原生方法,用于判断一个值是否为数组。我们需要手动实现这个方法,能够准确判断各种情况下的数组类型,包括跨iframe的数组对象。
解答
/**
* 实现 Array.isArray 方法
* @param {*} value - 需要判断的值
* @returns {boolean} - 是否为数组
*/
function myIsArray(value) {
// 方法一:使用 Object.prototype.toString.call()
return Object.prototype.toString.call(value) === '[object Array]';
}
// 方法二:使用 instanceof(存在跨iframe问题)
function myIsArray2(value) {
return value instanceof Array;
}
// 方法三:使用 constructor 属性(可能被修改)
function myIsArray3(value) {
return value && value.constructor === Array;
}
// 方法四:使用 Array.prototype.isPrototypeOf
function myIsArray4(value) {
return Array.prototype.isPrototypeOf(value);
}
// 推荐使用方法一,最可靠
if (!Array.isArray) {
Array.isArray = function(value) {
return Object.prototype.toString.call(value) === '[object Array]';
};
}
使用示例
// 基本类型测试
console.log(myIsArray([])); // true
console.log(myIsArray([1, 2, 3])); // true
console.log(myIsArray(new Array())); // true
// 非数组类型测试
console.log(myIsArray({})); // false
console.log(myIsArray('array')); // false
console.log(myIsArray(123)); // false
console.log(myIsArray(null)); // false
console.log(myIsArray(undefined)); // false
// 类数组对象测试
console.log(myIsArray({ length: 0 })); // false
console.log(myIsArray(arguments)); // false
// 特殊情况测试
const arrayLike = {
0: 'a',
1: 'b',
length: 2
};
console.log(myIsArray(arrayLike)); // false
// TypedArray 测试
console.log(myIsArray(new Int8Array())); // false
console.log(myIsArray(new Uint8Array())); // false
// 跨iframe场景(方法一可以正确识别)
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = window.frames[0].Array;
const arr = new iframeArray(1, 2, 3);
console.log(myIsArray(arr)); // true
console.log(myIsArray2(arr)); // false (instanceof失效)
关键点
-
Object.prototype.toString.call() 是最可靠的方法:返回对象的内部
[[Class]]属性,格式为[object Type],不会受到原型链修改的影响 -
instanceof 的局限性:在跨 iframe 场景下会失效,因为不同 iframe 有不同的 Array 构造函数
-
constructor 属性不可靠:可以被手动修改,不适合作为类型判断的依据
-
polyfill 实现:在不支持
Array.isArray的环境中,可以通过检测并添加该方法来实现兼容 -
与类数组对象的区别:真正的数组和类数组对象(如 arguments、NodeList)有本质区别,
Array.isArray只对真正的数组返回 true -
TypedArray 不是 Array:虽然 TypedArray(如 Int8Array)也是数组形式,但它们不是 Array 的实例
目录