当涉及到检测数据的问题时,我们首先想到的可能就是用typeof来检测数据类型。
其中typeof返回示例如下:
// 数值
typeof 23 === 'number';
// 字符串
typeof '' === 'string';
// 布尔值
typeof false === 'boolean';
// Symbols
typeof Symbol() === 'symbol';
// Undefined
typeof undefined === 'undefined';
// 对象
typeof {
a: 1 } === 'object';
typeof [1, 2, 4] === 'object';
// 函数
typeof function () {
} === 'function';
//注意:
// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
由上例我们可以看出,对于Function, String, Number, Undefined等这几种基本类型来说,我们可以采用typeof检测。
但是对于数组或者正则(由一个字符序列形成的搜索模式)来说,typeof检测无法满足,因为两者的返回类型都是对象object,所以我们还需另找方法…
instanceof可以判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上,所以用来检测某对象是否是数组可能更好不过了,直接通过看返回值true与false直接可以判断是否是数组。
代码如下(示例):
console.log([] instanceof Array); // true
console.log({
a: 1 }instanceof Array); // false
同样 由于js中每一个对象都有一个constructor属性,它引用了初始化该对象的构造函数,比如判断未知对象的类型。
代码如下(示例):
//方法重写
function isArray(obj) {
return typeof obj == 'object' && obj.constructor == Array
}
// 测试de
console.log(isArray([])); // true
var a = {
"a":1};
console.log(isArray(a)); // false
var b = [1,2,3];
console.log(isArray(b)); // true
console.log(isArray(/\d+/g)); // false
如上可以看到,通过调用prototype属性与isArray 方法一般情况下可以判断是否为数组的列子
但是这种一般情况真的可以完全判断吗?答案当然是否定的,当对于跨框架iframe的时候使用页面中的数组时:
代码如下(示例):
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray("1","2","3","4","5");
//这个写法IE下是不支持的,标准浏览器firefox,chrome下有
console.log(arr); // 打印出 ["1", "2", "3", "4", "5"]
console.log(arr instanceof Array); // false
console.log(arr.constructor === Array); // false
失败的关键在于iframe元素的跨平台的特点,使其有一套自己的执行环境,创建的数组无法共享其prototype属性,由于无法共享原型链,所以无法采用如上两种方式判断。
以上三种方法都无法准确判断对象是否为数组,有没有比较准确的方法呢,答案当然是肯定的。
function isArray(obj) {
return Object.prototype.toString.call(obj) == '[object Array]'; //call是用来改变指向的
} //方法重写
// 代码调用
//一般情况
console.log(isArray([])); // true
console.log(isArray([1,2,3])); // true
//判断特殊情况,跨平台框架
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray("1","2","3","4","5");
console.log(arr); // ["1","2","3","4","5"]
console.log(isArray(arr)); // true ~
这时候,可能又有人要说了,这种原型链的方法这么麻烦,有简单一点的吗,当然ECMA-262为我们引入了Array.isArray()方法。
isArray方法用来准确判断一个值是否为数组,对于IE9+、 Firefox 4+、Safari 5+、Opera 10.5+和Chrome都可以完美兼容,但是对于IE8之前的版本是不支持的。
但是个人感觉用法来说是最为简便的:
Array.isArray([]) // true
对于判断一个对象是数组的问题上,最好的方式如下:
var arr = [1,2,3];
var arr2 = [{
name : 'jack', age : 22 }];
function isArrayFn(value){
// 判断Array.isArray的兼容性
if (typeof Array.isArray === "function") {
return Array.isArray(value);
}else{
return Object.prototype.toString.call(value) === "[object Array]";
// return obj.__proto__ === Array.prototype;
}
}
console.log(isArrayFn(arr)); // true
console.log(isArrayFn(arr2)); // true
补充:原生链的方法不仅看起来较为麻烦,而且执行效率也几乎慢了Array.isArray()一倍,所以我们为了提高代码的执行效率,所以我们可以最先判断Array.isArray()的兼容性问题,之后再考虑选取原型链的方法。