JavaScript 在类型判断上确实是有比较多的坑,在不使用 ES5 的 Array.isArray() 的状况下,如何判断呢?javascript
javascript 弱类型的语言就是有比较多的坑,单纯的typeof 是很无力的。因此用它来判断数组确定是不行的。java
typeof 1 // number typeof undefined // undefined typeof null // object typeof [] // object typeof {} //object typeof function (){} // function
那么言归正传正传,该如何判断。数组
Array 对象都是有length 属性的,可不能够判断lengthapp
function isArray(array) { return (typeof array === 'object' && typeof array.length === 'number') }
与这个相似的是函数
function isArray(array) { return (typeof array === 'object' && !isNaN(array.length)) }
可是这个存在的问题是,对于有length属性的对象,则会出现判断失误的问题
好比:.net
var fakeArray = { length: 10, value: 'Fake Array' }
var arr = [1, 2, 3] arr instanceof Array // constructor 指向了原型 arr.constructor === Array
但在多iframe的状况下,因为每一个iframe 是一个独立的环境,它们之间不不共享原型链,则经过原型进行判断会出现错误prototype
var iframe = document.createElement('iframe') document.body.appendChild(iframe) xArray = window.frames[window.frames.length-1].Array var arr = new xArray(1,2,3) // [1,2,3] // 正确的判断 Array.isArray(arr) // true // 有问题的判断 arr instanceof Array // false arr.constructor === Array // false
适用于全部环境,只支持原生的对象,Object的toString()方法不能检测非原生构造函数的构造函数名。开发人员自定义的任何构造函数都将返回[object Object]。在任何值上直接调用Object的原生toString()方法,都会返回[object NativeConstrctorName]格式的字符串,每一个类内部都有一个class属性,这个属性中就指定了上述字符串中构造函数名。
code
Object.prototype.toString.call(array) === '[object Array]'
不过,上面的方案也存在必定问题,在ES6 中这样的判断能够被欺骗htm
var obj = {}; // ES6 Symbol obj[Symbol.toStringTag] = 'Array'; // true console.log(isArray(obj));
在ES5 以后,就老老实实用Array.isArray 来判断,ES5以前能够使用上面pollyfill。对象
if (!Array.isArray) { return Object.prototype.toString.call(array) === '[object Array]'; }
以此延伸,那么判断其余类型就能够使用相似的方法
var is = function (obj,type) { return (type === "Null" && obj === null) || (type === "Undefined" && obj === void 0 ) || (type === "Number" && isFinite(obj)) || Object.prototype.toString.call(obj).slice(8,-1) === type; }
参考: