要判断js中某个变量的类型,我首先想到的是用 typeof 这个函数,但是这个函数只有在判断值类型的变量类型时有效,如:
表达式 返回值
typeof(0) number
typeof("a") string
typeof( false) boolean
typeof( function(){}) function
var a; typeof(a) undefined
typeof(0) number
typeof("a") string
typeof( false) boolean
typeof( function(){}) function
var a; typeof(a) undefined
在判断引用类型变量时却不灵光了,因为它们都返回object,如:
表达式 返回值
typeof( null) object
typeof([]) object
typeof( new Date()) object
typeof( new Object()) object
typeof( null) object
typeof([]) object
typeof( new Date()) object
typeof( new Object()) object
这时候咋办呢?经研究jquery以及其他js框架源码发现,它们普遍采用的Object.prototype.toString.call(val)的方法,如:
var t=Object.prototype.toString;
表达式 返回值
t.call(0) [object Number]
t.call("a") [object String]
t.call( false) [object Boolean]
t.call( function(){}) [object Function]
var a;t.call(a) [object Undefined]
t.call( null) [object Null]
t.call([]) [object Array]
t.call( new Date()) [object Date]
t.call( new Object()) [object Object]
表达式 返回值
t.call(0) [object Number]
t.call("a") [object String]
t.call( false) [object Boolean]
t.call( function(){}) [object Function]
var a;t.call(a) [object Undefined]
t.call( null) [object Null]
t.call([]) [object Array]
t.call( new Date()) [object Date]
t.call( new Object()) [object Object]
Object.prototype.toString.call本质上进行了两步操作:
首先获取对象的类名(对象类型),然后将[object、获取的类名、]组合并返回
标准浏览器中完美的作到,但是(为什么要说但是呢)IE6中,却会出现以下问题:
通过Object.prototype.toString.call获取的undefined,null均为Object
问题貌似解决了。可是如果要判断的是一个自定义的js对象呢?如:
function people(){};
var a= new people();
t.call(a) 会返回什么呢? 答案是:[object Object]
var a= new people();
t.call(a) 会返回什么呢? 答案是:[object Object]
这时候咋办?
Javascript中,一切皆为对象,是对象,就有prototype属性(Global 和 Math 除外),prototype有一个属性constructor,这个属性保存了对构造特定对象实例的函数的引用,如:
function people(){};
people.constructor==Function 返回 true
people.prototype.constructor==people 返回 true
var a= new people();
a.constructor==people 返回 true
people.constructor==Function 返回 true
people.prototype.constructor==people 返回 true
var a= new people();
a.constructor==people 返回 true
但是(又是但是),比如要给people这个类增加一个setName方式,一般有两种写法:
people.prototype.setName=
function(){
/**/}
和
people.prototype={setName:
function(){
/**/}}
当此类继承其他类时,还会有第三种写法
people.prototype=
new xxx();
people.prototype.setName= function(){ /**/}
people.prototype.setName= function(){ /**/}
当使用第二写法时,
var a=
new people();a.constructor 的返回值却是Object,原因很简单,因为 people.prototype 也是一个对象,是引用类型,当执行
people.prototype={setName:
function(){
/**/}}
操作时,相当于执行以下操作:
var _p={setName:
function(){
/**/}};
people.prototype=_p;
people.prototype=_p;
people.prototype 的指向就变了,变得跟 _p 一致了,而_p的constructor指向的是的却是Object,a.constructor调用的是people.prototype.constructor,people.prototype与_p的引用相同,所以a.constructor 的返回值也就是Object了
同理可得,当用第三种写法,返回的是那个xxx的类型
ps:以下表达式都会返回 true
"a".constructor==String
false.constructor==Boolean
( function(){}).constructor==Function
(1).constructor==Number
[].constructor==Array
( new Date()).constructor==Date
( new Object()).constructor==Object
但是undefined 和 null 的 没有constructor,因为这两个值都没有实例化
false.constructor==Boolean
( function(){}).constructor==Function
(1).constructor==Number
[].constructor==Array
( new Date()).constructor==Date
( new Object()).constructor==Object
但是undefined 和 null 的 没有constructor,因为这两个值都没有实例化
所以,我们又要悲催的先对以上类型进行判断,完整代码:
function typeOf(value) {
if ( null === value) {
return 'null';
}
var type = typeof value;
if ('undefined' === type || 'string' === type) {
return type;
}
var typeString = Object.prototype.toString.call(value);
switch (typeString) {
case '[object Array]':
return 'array';
case '[object Date]':
return 'date';
case '[object Boolean]':
return 'boolean';
case '[object Number]':
return 'number';
case '[object Function]':
return 'function';
case '[object RegExp]':
return 'regexp';
case '[object Object]':
if (undefined !== value.nodeType) {
if (3 == value.nodeType) {
return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
} else {
return 'element';
}
} else {
var _ = (value.constructor + "").match(/^(\s)*function(\s)+[$_a-zA-Z0-9]+(\s)*\(/ig);
if (_ && _.length > 0) {
_ = _[0].replace("function", "").replace("(", "").replace(/\s/g, "");
return _;
} else
return 'unknow';
}
default:
return 'unknow';
}
}
if ( null === value) {
return 'null';
}
var type = typeof value;
if ('undefined' === type || 'string' === type) {
return type;
}
var typeString = Object.prototype.toString.call(value);
switch (typeString) {
case '[object Array]':
return 'array';
case '[object Date]':
return 'date';
case '[object Boolean]':
return 'boolean';
case '[object Number]':
return 'number';
case '[object Function]':
return 'function';
case '[object RegExp]':
return 'regexp';
case '[object Object]':
if (undefined !== value.nodeType) {
if (3 == value.nodeType) {
return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
} else {
return 'element';
}
} else {
var _ = (value.constructor + "").match(/^(\s)*function(\s)+[$_a-zA-Z0-9]+(\s)*\(/ig);
if (_ && _.length > 0) {
_ = _[0].replace("function", "").replace("(", "").replace(/\s/g, "");
return _;
} else
return 'unknow';
}
default:
return 'unknow';
}
}