范例检测
在js中供应两种检测范例的要领,然则它们并不老是靠谱。
typeof
instanceof
下面我们来看看各个范例的应当怎样举行检测比较靠谱
1. 基础范例
基础范例(除null以外)的检测运用typeof
,它的语法很简单
var number = 1,
string = "s",
boolean = true,
un = undefined,
typeof number; // "number"
typeof string; // "string"
typeof boolean;// "boolean"
typeof un; // "undefined"
1.2 null
假如我们运用typeof来检测,效果会是
var n = null;
typeof n;//"object"
有人说这是个bug,有人说这是由于null自身就代表着一个空对象,我们也经经常使用null来消除援用。不管怎么说,我们能够如许检测null
var n = null;
function isNull(n){
if(!n && typeof n !== "undefined"){
return true;
}
return false;
}
isNull(n);// true
1.3 非数字
推断一个变量是不是是数字,能够运用isNaN(),这个要领的意义是is not a numher
,也就是说返回true的时刻申明变量不是一个数字。
var a = 1,
b = "s",
c = "1";
isNaN(a); // false
isNaN(b); // true
isNaN(c); // true
2. 援用范例
援用范例运用typeof检测,返回都是”object”。这实在没什么意义,我们要知道的是变量细致是哪一个援用范例的,比方数组,自定义的范例等等。这个时刻能够用instanceof,它的语法是
实例 instanceof 对象组织函数
var arr = [];
arr instanceof Array; // true
function Person(){};
var p = new Person();
p instanceof Person; // true
instanceof不仅能检测组织对象的组织器,还检测原型链。
var now = new Date();
now instanceof Date; // true
now instanceof Object; // true
2.1 数组检测
数组在编程中相称罕见,在框架中也是,怎样正确地检测数组范例,是相称主要的。
能够有人会说了,运用instanceof不就能够了。非也。在js中,有一个很陈旧的跨域题目:在iframe之间往返通报数组,而instanceof不能跨帧。
什么叫不能跨帧?假设在一个浏览器的帧(frame A)里的一个对象传入到别的一个帧(frame B)中,两个帧都定义了一个组织函数Person,假如来自帧A的对象是帧APerson的实例,则
frameAPersonInstance instanceof frameAPerson; //true
frameAPersonInstance instanceof frameBPerson; //false
那怎么办?
起首,有人提出了运用duck typing
的思绪来处置惩罚这个题目,duck typing
的意义就是:像鸭子一样走路、泅水而且嘎嘎叫的就是鸭子,这是个很有意义的主意,它的实质就是我们关注对象能做什么,不是关注对象是什么,采纳如许的思绪,我们检测对象实例是不是有sort属性来推断对象实例是不是是一个数组,细致完成以下
function isArray(value) {
return typeof value.sort === "function";
}
以后,kangax发现了一个很风趣的征象,挪用某个值的内置toString()要领在一切浏览器中都返回规范的字符串效果,关于数组来讲,返回的字符串为”[object Array]”,这个要领对辨认内置对象都异常有用,因而jq也是采取了这类体式格局来完成的isArray()的要领。
function isArray(value) {
return Object.prototype.toString.call(value) === "[object Array]";
}
以后,ECMA5将Array.isArray()正式引入JavaScript,供应了一个能正确检测一个变量是不是为数组范例的
Array.isArray(variable);
3. 末了
到这里,你认为已处置惩罚了一切的范例检测题目了吗?并非。在《JavaScript框架设想》这本书中,细致地议论各种范例检测的兼容性题目,而且在massframework
给出了一个很不错的完成,从代码内里来进修能够学到更多。
// 竖立范例的映照
var class2type = {
"[objectHTMLDocument]" : "Document",
"[objectHTMLCollection]" : "NodeList",
"[objectStaticNodeList]" : "NodeList",
"[objectIXMLDOMNodeList]" : "NodeList",
"[objectDOMWindow]" : "Window",
"[object global]" : "Window", //safari 4.04
"null" : "null",
"NaN" : "NaN",
"undefined" : "undefined"
};
// 一般情况下的范例
"Boolean,Number,String,Function,Array,Date,RegExp,Window,Document,Arguments,NodeList"
.replace(/[^, ]/g, function(name) {
class2type['[object ' + name + ']'] = name;
});
var toString = class2type.toString;
mass.type = function(obj,str){
var result = class2type[ (obj == null || obj !== obj) ? obj : toString.call(obj) ]
|| obj.nodeName || '#';
if(result.charAt(0) === '#' ){ //兼容旧版浏览器与处置惩罚个别情况,如window.opera
//hack,应用IE6,IE7,IE8 window == document 为 true,document == window 为 false的特征
if(obj == obj.document && obj.document != obj){
result = 'Window';
} else if (obj.nodeType === 9){ //nodeType 属性返回以数字值返回指定节点的节点范例。9代表document
result = 'Document';
} else if (obj.callee){ //arguments 特有的属性
resutl = 'Arguments';
} else if (isFinite(obj.length) && obj.item){ //obj.item()要领,可返回节点列表中处于指定的索引号的节点。
result = 'NodeList';
} else {
result = toString.call(obj).slice(8,-1); //[object XXXX]
}
}
//供应一个举行范例比较的功用
if(str){
return str === result;
}
return result;
}
4. 参考
《编写可保护的JavaScript》
《JavaScript框架设想》