JavaScript类型检测小结(上)
老话题了,各种方案和相关讨论都不少,简单总结下:
悠久的typeof
JavaScript里只有五种基本数据类型:number, string, boolean, null, undefined. 其它的都是复合数据类型object.
值和数据类型是两码事。比如:null是null类型的唯一值,undefined是undefined类型的唯一值,就如true和false是boolean类型的唯两值一样。
可以用typeof检测出以下6种数据类型:number, string, boolean, undefined, object, function.
注意:typeof null == “object”. null类型的唯一值null的类型是object类型。(很拗口,但事实就是这样)
因此,对于五种基本数据类型来说,用下面的代码就可以检测出来:
// 获取变量o的数据类型
function type(o) {
return (o === null) ? 'null' : typeof(o);
}
instanceof的作用
typeof只能检测基本数据类型,对于复合数据类型,除了function,都通通返回'object'.
instanceof可以检测某个对象是不是另一个对象的实例,注意instanceof的右操作数必须为对象:
alert(1 instanceof Number); // false
alert({} instanceof Object); // true
instanceof还可以检测父类型:
function Animal() {};
function Pig() {};
Pig.prototype = new Animal();
alert(new Pig() instanceof Animal); // true
可以看出,instanceof不适合用来检测一个对象本身的类型。
救命稻草:constructor
JavaScript里的所有对象都拥有一个constructor属性,但JavaScript里并非一切都是对象:
alert(1.constructor); // 报错
var o = 1;
alert(o.constructor); // Number
o = null; // or undefined
alert(o.constructor); // 报错
alert({}.constructor); // Object
alert(true.constructor); // Boolean
可以看出,null和undefined没有constructor,number和string数据类型的字面量,也没有constructor,但number和string数据类型的变量有constructor(在寻找constructor属性时,会自动转换成Number或String对象)。
下面是Johg Resig《Pro JavaScript Techniques》书中的一张表:

这样,对于复合数据类型,我们可以采用下面的方法检测:
...
isArray: function(arr) {
return !!arr && arr.constructor == Array;
}
...
jQuery 1.2中采用的就是上面的代码。
一切看起来很完美,然而不安分的iframe总喜欢来捣点鬼:
// 请在非ie浏览器中运行
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1, 2, 3); // [1,2,3]
alert(arr.constructor === Array); // false
原因很简单:不同frame中的Array拥有不同的constructor.
鸭子也上场:Duck Typing
在犀牛书里,提到一句老话:“如果走路像鸭子,叫声也像鸭子,那它就是一个鸭子!” 换言之,对于Array来说,如果一个对象有splice和join属性,那它就是Array. 这就是Duck Typing:
function isArray(o) {
return o != null && typeof o === ‘object’ &&
'splice' in o && 'join' in o;
}
上面是Prototype 1.6中的代码。
显然,鸭子检测很容易误把自造的天鹅也当成鸭:
alert(isArray({'splice': '', 'join': ''})); // true
鸭子检测的一个用途是,可以用来检测类似对象,比如类数组:
function isArrayLike(x) {
if (x instanceof Array) return true; // Real arrays are array-like
if (!('length' in x)) return false; // Arrays must have a length property
if (typeof x.length != 'number') return false; // Length must be a number
if (x.length < 0) return false; // and nonnegative
if (x.length > 0) {
// If the array is nonempty, it must at a minimum
// have a property defined whose name is the number length-1
if (!((x.length - 1) in x)) return false;
}
return true;
}
上面的代码摘自犀牛书。
时间太晚,今天就写到这。留两个问题:
- constuctor示例中,
var xArray = window.frames[window.frames.length-1].Array;能否写成var xArray = iframe.Array;?为什么? - JavaScript中,一切皆是对象。这句话究竟对不对?为什么?
晚安,朋友们!
下篇写好了:JavaScript类型检测小结(下)

February 5th, 2009 on 8:41
Duck typing的作用就是约定一种行为接口,是一种比声明式接口更适合动态语言的方式。因此Prototype里面才会有Enumerable这样的Module,对于Array、Hash、或者element collection它们具有类似的行为,所以它们都是Enumerable。所以不会存在天鹅也是鸭子的问题,而应该说天鹅好像鸭子一样。
February 5th, 2009 on 10:20
1楼说得对
Duck typing就是用来关心对象的行为,而不是它是什么类型的。一个Duck typing的方法可以处理有相同行为的不同类型对象。而不是用这种方法来检查类型的。
February 5th, 2009 on 16:21
公布问题1的答案:
因此文中的代码可以稍微简化为:
var iframe = document.createElement('iframe'); document.body.appendChild(iframe); var xArray = iframe.contentWindow.Array; var arr = new xArray(1, 2, 3); // [1,2,3] alert(arr.constructor === Array); // falseFebruary 7th, 2009 on 13:32
alert(1['constructor']);
alert(1.constructor); // 肯定报错,’.'在这里小数点
February 8th, 2009 on 10:21
还有一种写法是:
alert(1..constructor)February 10th, 2009 on 11:44
YUI也用的鸭子检测:
isArray: function(o) {
if (o) {
return L.isNumber(o.length) && L.isFunction(o.splice);
}
return false;
},
April 30th, 2009 on 15:00
其实整型字面量需要有个空格:
alert(1 .constructor);
或
alert(1
.constructor);
1.constructor实际上是1.0constructor,当然就出错了
而1..constructor实际上是1.0.constructor,这个也是不会出错的,只不过已经不是整型了。
当然,JavaScript里不分整型和浮点。
September 9th, 2009 on 21:08
function isArray(v) {
return Object.prototype.toString.call(v) === “[object Array]” ? 1 : v.callee || (typeof v.item != “undefined” && !v.nodeType && !v.alert) ? 2 : 0;
};
Array,HtmlCollection,arguments
leave a reply