摘要:
1.数组检测的方法:
1) typeof 、
2) instanceof 、
3) constructor 、
4) Object.prototype.toString、
5) Array.isArray()。
以上为数组检测的方法,但是这些方法中:
Array.isArray()方法是最为简单方便的方法,但是存在版本支持性问题,没有版本支持性问题且较好的检测方法是使用Object.prototype.toString结合call()方法来检查,通常数组检测中我们常用的做法是两种方法结合。
原型链,在使用数组检测方法时我们要对原型链有深刻的理解,才能知道使用该数组检测方法的实际原理是什么。关于原型链的理解,可以看我写的这篇博客:http://www.cnblogs.com/novice007/p/7764583.html
构造函数,使用构造函数的方法检测数组,这是很大的一个坑,因为构造函数是能够被重写的,所以所得结果就不正确。例如:
1)var arr = [];
arr.constructor === Array; //返回true
2)var arr = 'abc';
arr.constructor = Array;
arr.constructor === Array; //返回true
因为constructor能够被重写,所以从例2可以很明显的知道arr不是数组,但是它被数组重写了,所以返回true。
方法简介
1.typeof方法
typeof方法是判断数据的类型。在JavaScript中基本数据类型有number、null、Boolean、string、array、object、functionv、undefined等。其typeof()方法检测返回值分别为:
1)字符串(string),typeof()的返回值为string,例如typeof(‘97900’)==》返回string。
2)函数类型(function),typeof()的返回值为function,例如typeof(RegExp)==》返回function。
3)数组(array)、对象(object)、null,typeof()的返回值都为object,例如typeof(null)、typeof(document),typeof([1,3,4,8])==》返回object。
4)布尔类型(Boolean),typeof()的返回值为Boolean,例如typeof(true)==》返回Boolean。
5)数字类型,typeof()的返回值为number,例如typeof(1)==》返回number。
6)对于未定义的变量,typeof()检测结果都返回undefined。
说明:由上面typeof方法对各个数据类型的检测返回值可知typeof方法不能够准确的检测一个数据是否是数组,因为typeof方法对对象、数组、null的检测结果都是返回object,我们并不能够知道该数据是否为对象还是数组。从中我们也可以得知在使用 typeof 运算符时采用引用类型存储值会有一些问题,就是不管引用的是什么类型的对象,它都返回 “object”。
2.instanceof方法
instanceof方法是用来判断一个对象是否是当前类的一个实例,也可以在继承关系中用来判断一个实例是否属于它的父类型,返回值为true或false。如下例子:
1)console.log(Object instanceof Object);//true
console.log(Function instanceof Function);//true
console.log(Number instanceof Number);//false
console.log(String instanceof String);//false
console.log(Function instanceof Object);//true
2)instanceof方法在继承关系中用来判断一个实例是否属于它的父类型。
function A(){}
function B(){}
B.prototype = new A();//JavaScript 原型继承
var C = new B();
console.log(C instanceof B)//true
console.log(C instanceof A)//true
说明:这里大家可能比较好奇,为什么只有Object和function的instanceof返回值为true,其它的(a instanceof a)返回值都为false,对于这个问题,大家可以在https://www.ibm.com/developerworks/cn/web/1306_jiangjj_
jsinstanceof/这篇文章中看看,这篇文章中对instanceof的用法讲解的非常的清楚,这里我就不再说明。Instanceof用法用法很强大,但是instanceof也不是判断数组的好方法,原因我们再通过下面这个例子说明一下:
window.οnlοad=function(){
Var iframe_arr=new window.frames[0].Array;
alert(iframe_arrinstanceof Array); //返回 false
}
出现这个问题的原因简单的说是因为在不同框架(iframe)中创建的数组不会相互共享其prototype属性。
原型链:
ECMAScript中对原型链的概念进行了描述,通过查阅了ECMAScript高级程序设计书,原型链的基本思想就是利用原型让一个引用类型继承另外一个引用类型的属性和方法。通俗的说原型链就是通过构造函数、原型与实例之间形成的一种链试关系,每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象内部的指针。对于更多的原型和原型链知识我就不在这里一一的说明了,大家可以通过查阅资料,进入更深的理解。
3.constructor 方法
使用constructor 方法判断数组的原理是因为每个实例都有与之对应的构造函数,我们可以通过判断它的构造函数,从而判断它属于哪个类型。但是该方法也存在不足,因为构造函数它能够被重写从而导致判断不正确,不仅如此constructor方法与instanceof方法也存在相同的问题,即在不同框架(iframe)中创建的数组不会相互共享其prototype属性。通过下面这个例子我们能够很明显的知道,该判断是错误的。
var arr = 'abc';
arr.constructor = Array;
arr.constructor === Array; //返回true
4.Array.isArray() 方法
Array.isArray() 函数的返回值为Boolean类型,如果指定的参数是数组,则返回true,否则返回false。
var arr = [];
var res = Array.isArray(arr);// true
var arr = new Array();
var res = Array.isArray(arr);// true
var arr = [1, 2, 3];
var res = Array.isArray(arr);// true
var res = Array.isArray("an array");
document.write(res);//false
说明:该方法是很好的判断数组的方法,但是isArray() 在以下文档模式中不受支持:Quirks、Internet Explorer 6 标准模式、Internet Explorer 7 标准模式、Internet Explorer 8 标准模式。所以在使用isArray()时要做版本判断,该版本支持的时候就使用该方法,不支持的时候就使用object.prototype.to
String.call()方法,接下来将继续介绍object.prototype.toString.call()方法的使用。
5.object.prototype.toString.call() 方法
该方法的原理是通过toString()方法转换,直接输出对象的类型(class)属性。
1)判断基本类型:
Object.prototype.toString.call(null);//”[object Null]”
Object.prototype.toString.call(undefined);//”[object Undefined]”
Object.prototype.toString.call(“abc”);//”[object String]”
Object.prototype.toString.call(123);//”[object Number]”
Object.prototype.toString.call(true);//”[object Boolean]”
2)判断原生引用类型:
函数类型
Function fn(){console.log(“test”);}
Object.prototype.toString.call(fn);//”[object Function]”
日期类型
var date = new Date();
Object.prototype.toString.call(date);//”[object Date]”
数组类型
var arr = [1,2,3];
Object.prototype.toString.call(arr);//”[object Array]”
说明:这里大家可能会比较好奇,为什么不使用Object.toString呢?这是因为toString为Object的原型方法,而Array ,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串.....),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用Object.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。
总结
通过上面的简单讲解,我相信大家也能够清楚的知道,在数组判断中,最好的判断方法是Array.isArray() 方法和object.prototype.toString.call()方法,Array.isArray() 是最直接最简单数组判断方法,但是存在版本支持问题,所以在版本兼容的情况下我们就使用该方法。object.prototype.toString.call()方法也是很好的数组判断方法,它解决了跨iframe 失效的问题,并且不存在版本支持问题,但是使用object.prototype.toString.call()是我们假设object.prototype.toString没有被重写的理想情况,因为它也有可能被重写。所以通过一系列的判断与对比,得出了判断数组最好的办法。
var arr1 = [8,4,9];
var arr2 = [{ a : 1, b : 2 }];
function isArray(value){
if (typeof Array.isArray === "function") {
return Array.isArray(value);
}else{
return Object.prototype.toString.call(value) === "[object Array]";
}
}
alert(isArray(arr1));// true
alert(isArray(arr2));// true