JavaScript类型检测小结(下)
请先阅读:JavaScript类型检测小结(上)
回归简单:Object.toString
这个方法并不新奇,在犀牛书的 9.7 Determining Object Type 一节中,有详细的讨论,但一直没有引起注意(犀牛书太厚,仔细阅读过的人,在世界范围内看来都是凤毛麟角的)。直到老道(Douglas Crockford)的火星文出现:The Miller Device(号召大家都向老道学习,多挖掘有价值的火星知识):
Object.prototype.toString.apply(value) === '[object Array]'
ECMA-262中的解释:
Object.prototype.toString( )
When the toString method is called, the following steps are taken:
1. Get the [[Class]] property of this object.
2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.
3. Return Result (2)
这样,就有了:
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
}
因为是字符串比较,也就解决了跨iframe的问题。
结合typeof和toString方法,可以比较完美的实现对JavaScript基本类型和内置对象的探测了:
var _toS = Object.prototype.toString,
_types = {
'undefined' : 'undefined',
'number' : 'number',
'boolean' : 'boolean',
'string' : 'string',
'[object Function]' : 'function',
'[object RegExp]' : 'regexp',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object Error]' : 'error'
};
function type(o) {
return _types[typeof o] || _types[_toS.call(o)] || (o ? 'object' : 'null');
}
详细测试页面请参考这里:typeof.js
自定义对象惹的祸
来看下面的代码:
function Animal() {}
function SubArray() {}
SubArray.prototype = [];
var toString = Object.prototype.toString;
alert(toString(new Animal()));
alert(toString(new SubArray()));
// firefox: [object Window]
// ie: [object Object]
// chrome: [object global]
alert(new SubArray() instanceof Array); // true
alert(new Animal() instanceof Animal); // true
可以看出,Object.toString方法,对于非内置对象来说,在各个浏览器下返回的值各异。
因此,如果要检测非内置对象,还是得用constructor和instaceof. 或者像Mootools一样,通过框架的机制来判断:
Mootools has an interesting approach with it’s $type function. Mootools wraps all native objects via the “Native” constructor in order to easily implement new methods for them. The Native constructor also creates a new property, called $family, which is the value returned by the $type() utility function.
好了,本文结束。JavaScript,每天精进一点点,乐哉!
参考资料
- 文中提到的犀牛书指的是:OReilly.JavaScript.The.Definitive.Guide.5th.Edition.Aug.2006
- How to write a robust ‘isArray’(很详细的介绍,一步一步,很有条理)
- The Miller Device(老道的文章总是言简意赅,一针见血……)
- getClass.js(toString方法检测Class的一个实现)
- typeof增加版(很不错的实现方案)
- toString in MDC(Mozilla是与时俱进的官方)

February 7th, 2009 on 9:26
winter:
这个其实跟浏览器类型检查是一个道理 对象类型检查不如对象属性检查
鸭子类型的本意其实不是prototype那样用的 跟下面这句话一个道理:
小心伪特性探测:比如if(window.ActiveXObject) { // 一大堆针对ie但和ActiveXObject没任何关系的代码 }
还有就是
typeof检查type
Object.toString检查私有属性[[class]]
constructor检查公有constructor
instanceof实际上检查的是私有属性[[prototype]]
这些东西你说它是类型确实挺像 但是其实混到一起也没什么价值
February 7th, 2009 on 9:26
hax:
1.xxx 不行,不是因为 1 上面没有 xxx,而是语法不合。写成(1).xxx就可以了。也就是说number和string其实都是有constructor属性的。当然这实际隐含了primitive到object的自动转换。
February 10th, 2009 on 10:01
hax: try
最神奇的当属item了
April 2nd, 2009 on 10:06
_toS.call(o) 是不是可以用
o + ”
来代替?
April 2nd, 2009 on 10:58
测试了一下,o + ” 不行。
打扰了。
May 13th, 2009 on 1:37
刚好在找这方面的文章,看了你写的文章后所有的问题就全解决了,也偷偷的把这篇文章收藏到了我的博客上了。
不过我在测试的时候发现用parseInt处理后的NaN还是当成number类型的。我现在在用JAVASCRIPT做ASP的,所以对数据检测要求比较高,我就加了判断NaN的代码进去,请你帮我看下我这样修改对不对?
function type(o){
if (typeof o.length == ‘number’){
if (o.callee) return ‘arguments’;
else if (o.item) return ‘collection’;
}
var _toS = Object.prototype.toString,
_types = {
‘undefined’ : ‘undefined’,
‘number’ : ‘number’,
‘boolean’ : ‘boolean’,
’string’ : ’string’,
‘[object Function]‘ : ‘function’,
‘[object RegExp]‘ : ‘regexp’,
‘[object Array]‘ : ‘array’,
‘[object Date]‘ : ‘date’,
‘[object Error]‘ : ‘error’
};
var _S=_types[typeof o] || _types[_toS.call(o)] || (o ? ‘object’ : ‘null’);
return (typeof o==’number’&&isNaN(o)?’nan’:_S);
}
leave a reply