当前位置: 首页 > 图文教程 > 网络编程 > Javascript > JavaScript类型检测小结

Javascript
JS+XML 省份和城市之间的联动实现代码
ie与firefox下的event使用说明与详细区别
Jquery 学习笔记(二)
jQuery技巧大放送 学习jquery的朋友可以看下
使用jQuery简化Ajax开发 Ajax开发入门
jQuery入门 构造函数
JavaScript iframe的相互操作浅析
JavaScript null和undefined区别分析
JavaScript 替换Html标签实现代码
jQuery 标题的自动翻转实现代码
JavaScript读取中文cookie时的乱码问题的解决方法
JavaScript 动态创建VML的方法
JavaScript Array扩展实现代码
javascript线性渐变一
javascript 线性渐变二
javascript 线性渐变三
滑动门式菜单 实现代码
extjs 学习笔记(三) 最基本的grid
javascript 操作cookies及正确使用cookies的属性
JavaScript 基础知识 被自己遗忘的

Javascript 中的 JavaScript类型检测小结


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 205 ::
收藏到网摘: n/a

老话题了,各种方案和相关讨论都不少,简单总结下:

悠久的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》书中的一张表:
constructor

这样,对于复合数据类型,我们可以采用下面的方法检测:

...
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;
}

上面的代码摘自犀牛书。

时间太晚,今天就写到这。留两个问题:

  1. constuctor示例中,var xArray = window.frames[window.frames.length-1].Array;能否写成var xArray = iframe.Array;?为什么?
  2. 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,每天精进一点点,乐哉!