谈谈JavaScript类型检测
javascript内置的类型检测机制并非完全可靠。比如typeof操作符,并不能准确的判断数据是哪个类型,比如:数组和对象就不能通过typeof来区分。
typeof [] ==="object" ; // true typeof {} === "object"; // true
但是typeof用来区别对象与基本数据类型时就比较有用了。
基本数据类型检测
由于typeof对所有对象和数组类型返回的都是"object",所以它在区别对象与基本数据类型时才有用。一个值使用typeof操作符可能返回下列某个字符串,注意是字符串:
"undefined"表示这个值未定义
"boolean"表示这个值是布尔值
"string"表示这个值是字符串
"number"表示这个值是数值
"object"表示这个值是对象或null(注意:typeof null 将返回"object",不能准确地判断类型的合法性,因此不能用typeof来检测对象类型。)
"function"表示这个值是函数(注意:Safari第四版在对正则表达式使用typeof操作符时回返回"function",因此很难确定这个值到底是不是函数。)
引用类型检测
JavaScript引用类型有:Object、Array、Date、Error、RegExp、Function、基本包装类型(Boolean类型、Number类型、String类型)、单体内置对象(Global对象、Math对象)等。检测引用类型可以使用 instanceof 和 Object.toString()方法。
instanceof 运算符
instanceof运算符要求其左边的运算数是一个对象,右边的运算数则是对象类的名字。如果该运算符的左边的对象是右边类的一个实例,则返回true,否则返回false。例如:
var d = new Date(); d instanceof Date; // true d instanceof Object; // true d instanceof Number ; //false var a = []; a instanceof Array ; // true a instanceof Object; // true a instanceof RegExp; // false
但是利用instanceof 操作符确定某个对象是不是数组会有些问题,例如:
if( value instanceof Array ) { // do something }
instanceof 操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,那其实就存在两个以上不同的全局执行环境,从而存在两个以上不同的Array构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组就会分别具有各自的不同的构造函数。因此在第二个框架对传入的数组执行 value instanceof Array 就会返回false了,因为构造函数是不一样的。
Object.toString()检测对象类型
在任何值上调用原生的toString()方法,都会返回一个[object nativeConstructorName] 格式的字符串。每个类在内部都会有一个[[Class]]属性,这个属性就指定上述字符串中的构造函数名。例如:
// 检测数组类型 function isArray(value){ return Object.prototype.toString.call(value) == "[object Array]" } // 检测函数 function isFunction(value){ return Object.prototype.toString.call(value) == "[object Function]" } // 检测正则表达式 function isRegExp(value){ return Object.prototype.toString.call(value) == "[object RegExp]" }
注意:对于在IE中以COM对象形式实现的任何函数,isFunction() 都将返回false,因为它们并非原生的JavaScript函数。
jQuery检测对象类型也是用到了toString()方法,查看type()方法的实现可以看到:
//version:jquery-1.11.3
var class2type = {};
// Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); });
type: function( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ] || "object" : typeof obj; }
通过定义一个class2type对象把所有类型的toString()返回值通过键值对存储起来。在调用type方法时通过toString()方法返回值进行匹配,最后返回检测值的类型。
总结
在区别基本数据类型和对象类型时可以使用typeof运算符,对于对象的类型确定通常使用原生toString()检测,注意Object.prototype.toString() 本身也可能被修改。
以上是JavaScript类型检测的一些基础知识总结,干货不多,望各位大神指教,欢迎留言讨论。