你的位置:首页 > Java教程

[Java教程]JavaScript进阶内容1:各种检测


该文章主要用来介绍JavaScript中常用的一些对象检测判断方法,整理资源来自书本和网络,如有错误或说明不详之处,望评论提出,本菜定提名感谢……(本文章知识比较基础,大牛请看点再绕道^_^)

1.检测原始值(typeof)  结论:    JavaScript五种原始类型:字符串、数字、布尔值、undefined、null。其中前四种的类型检测请使用 typeof ,最后一种 null 的类型检测请使用恒等(===)或者非恒等(!==)运算符。  原因:    typeof 运算符返回一个表示值的类型的字符串,    如:    typeof(字符串)     => "string"    typeof(数字)     => "number"    typeof(布尔值)     => "boolean"    typeof(undefined)   => "undefined"    typeof 的基本语法是:      typeof 变量 //推荐语法      也可以使用:      typeof(变量) //虽然这是合法的,但这让 typeof 看起来更像是函数,而非运算符。    typeof 检测四种原始类型做法:    //检测字符串    if(typeof mytype === "string"){      ……    }    // 检测数字    if(typeof mytype === "number"){      ……    }    // 检测布尔值    if(typeof mytype === "boolean" && mytype){      ……    }    // 检测 undefined    if(typeof mytype ==="undefined"){      ……    }    最后一种是对 null 的检测,因为简单地把一个对象和 null 进行比较,不足以判断其值的类型是否合法,比如:    if(items !== null){//不好的做法      items.sort();//如果items不是数组,该执行将报错      items.foreach(function(item){        //执行一些逻辑      })    }    其实,items 是一个数组,但是仅仅通过和 null 比较,不足以判断其是合法的数组类型,因为tiems 也可以是1、字符串、对象等,都和 null 不相等。    因此,只有在你明确预见某个值真的是 null ,则可以直接和 null 比较,比如:    var element = document.getElementById("my-div");    if(element !== null){//因为 getElementById 要么返回节点,要么返回 null      ……    }    特别提示:typeof(null) 返回 "object",这被认为是标准规范的严重"bug",所以一定要杜绝使用 typeof 检测 null类型。2.检测引用值(instanceof)  结论:    JavaScript引用类型有:Object、Array、Date、Error、RegExp 等等。检测引用类型的最好方法是使用 instanceof 运算符(Array 无法跨帧,需另讲)。  原因:    不能使用 typeof 检测引用类型,因为所有对象都会返回"object":    typeof {} => "object"    typeof [] => "object"    typeof new Date() => "object"    typeof new RegExp() => "object"    所以不能用 typeof 来检测。    instanceof 意思是"实例",也就是说只要一个变量是某个对象(引用类型)的实例,则返回 true,如:    // 检测日期    if(value instanceof Date){      ……    }    // 检测正则表达式    if(value instanceof RegExp){      ……    }    // 检测 Error    if(value instanceof Error){      ……    }    另外,instanceof 还可以检测原型链,比如,所有对象都继承自 Object,所以 value instanceof Object 都会返回 true。    如:    var now = new Date();    now instanceof Object => true    now instanceof Date => true3.检测函数(typeof)  结论:    检测函数使用 typeof;而IE8及其更早浏览器中检测DOM的方法时(document.getElementById/document.createElement/document.getElementsByTageName……)时使用 in 运算符。  原因:    function 也是引用类型,虽然    function myFun(){}    console.log(myFun instanceof Function)// true    返回true,但是每个函数中都有自己的 Function 构造方法,如果跨帧(frame)使用,在另一个帧中就不会识别另一个帧中的实例对象。    建议使用 typeof,返回"function".    function myFun(){}    console.log(typeof myFun === "function")// true(推荐使用)    另外,在IE8和更早版本中,使用typeof 检测document.getElementById/document.createElement/document.getElementsByTageName……时,返回 "object"    推荐使用:    if("querySelectorAll" in document){      images=document.querySelectorAll('img');    }    虽然不是最理想的,如果想在IE8及其更早版本中使用,这无疑是最安全的。其他情况则使用 typeof 检测是否为函数。4.检测数组(Array.isArray + Object.prototype.toString.call(value) === '[object Array]' )  结论:    function isArray(value){      if(typeof Array.isArray === 'function'){        return Array.isArray(value);      }else{        return Object.prototype.toString.call(value) === '[object Array]';      }    }  原因:    最开始检测数组采用“鸭式辨型”:    function isArray(value){      return typeof value.sort === 'function';    }    因为目前只有数组才有排序 sort() 方法,但是如果传递的 value 包含自定义的 sort(),该方法就会失效。    目前比较流行的方法是:    function isArray(value){      return Object.prototype.toString.call(value) === '[object Array]';    }    该方法是基于 toString()方法在所有浏览器中都会返回标准的字符串结果。对于数组则返回 '[object Array]'。    由于ECMAScript5正式引用了 Array.isArray() 方法,IE9+、FireFox4+、Safari 5+、Opera 10.5+、Chrome都支持了该方法,所以    推荐使用:    function isArray(value){      if(typeof Array.isArray === 'function'){        return Array.isArray(value);      }else{        return Object.prototype.toString.call(value) === '[object Array]';      }    }5.检测属性(in 或 hasOwnProperty)  结论:    判断属性是否存在最好的方法是使用 in 运算符。只有需要判断实例属性时才会用到 hasOwnProperty。  原因:    有时候检测属性会这样使用:    //不好的写法:检测假值    if(object[propertyName]){      ……    }    //不好的写法:和 null 比较    if(object[propertyName] != null){      ……    }    //不好的写法:和 undefined 比较    if(object[propertyName] != undefined){      ……    }    以上的代码,是通过获取该属性值来判断是否包含该属性,但是如果该属性的值本身就是 false、0、""、null、undefined呢?是不是就不管用了!    所以,最好的办法是使用 in 运算符。in 仅仅只会判断属性是否存在,而不会获取属性值。如果只需要判断实例属性可以用 hasOwnProperty。    in vs hasOwnProperty:    in:判断对象(包括原型链)是否具备指定的属性。(有中说法叫:判断实例对象属性、或者继承自对象的原型的属性)    hasOwnProperty:判断对象自身(不包括原型链)是否具有指定名称的属性。 (有种说法叫:仅用于判断实例属性)    上面说明很晦涩,继续看就明白了:    先来对比几个关键词:    实例属性 vs 原型的属性 vs 静态属性:    先看代码:    function Man(myname, age) {       //定义实例属性       this.myname = myname;       this.age = age;     }    //定义静态属性    Man.sex = '男';     //定义原型属性     Man.prototype.phone = '123456';     document.writeln(Man.sex);//男    document.writeln(Man.myname);//undefined    document.writeln(Man.age);//undefined    document.writeln(Man.phone);//undefined    document.writeln(Man.prototype.phone);//123456    var man = new Man("Tom", 24);     document.writeln(man.myname);//Tom    document.writeln(Man.sex);//男    document.writeln(man.age);//24    document.writeln(man.phone);//123456    代码总结:    实例属性:构造函数中定义的属性,类似C#/java中 只能通过 new 实例化一个对象后才能访问到的属性。    原型属性:属于原型链中的属性,通过prototype扩展的属性。    静态属性:在构造函数外,直接通过【对象名.新属性】追加的属性叫静态属性,类似C#/java中的 static 属性。    言归正传,    in 和 hasOwnProperty 如何使用呢,看代码:    function Site(){      //判断是否有这些实例属性方法:s.hasOwnProperty("name/url...") 或 "name/url..." in s      this.name = "CodePlayer";      this.url = "http://www.365mini.com/";      this.sayHello = function(){        document.writeln("欢迎来到" + this.name);      };    }    Site.ower='Alec';//判断是否有静态属性方法:Site.hasOwnProperty('ower') 或 "ower" in Site    var obj = {      //判断是否有这些原型属性方法:"engine/sayHi.." in s (这些对象是s原型链中的对象,如果该obj又有更高级原型域,同样可以使用 '属性名' in s 判断)      engine: "PHP",      sayHi: function(){        document.writeln("欢迎访问" + this.url);      }    };    Site.prototype = obj;    var s = new Site();    document.writeln( s.hasOwnProperty("name") ); // true    document.writeln( s.hasOwnProperty("sayHello") ); // true    // 以下属性继承自原型链,因此为false    document.writeln( s.hasOwnProperty("engine") ); // false    document.writeln( s.hasOwnProperty("sayHi") ); // false    document.writeln( s.hasOwnProperty("toString") ); // false    //静态属性只能通过原型对象判断,无法用实例对象判断    document.writeln( s.hasOwnProperty("ower") ); // false    document.writeln( Site.hasOwnProperty('ower') );//true    // 想要查看对象(包括原型链)是否具备指定的属性,可以使用in操作符    document.writeln( "url" in s ); // true    document.writeln( "sayHello" in s ); // true    document.writeln( "engine" in s ); // true    document.writeln( "sayHi" in s ); // true    document.writeln( "toString" in s ); // true    document.writeln( "ower" in s ); // false    document.writeln( "ower" in Site ); // true 静态属性需要使用原型对象名访问
    附图一张,进一步说明:
    
看到这里,应该对 in 和 hasOwnProperty 的使用场景有所了解了吧? 最后,需要特别说明的一点是: IE8及其更早的IE版本中,DOM对象并非继承自Object,因此,无法使用hasOwnProperty()方法,换句话说,如果你在调用DOM对象的hasOwnProperty()方法之前需要先检测器是否存在(假如你已经知道对象不是DOM,就可以省略此步骤) //对于所有非DOM对象来说,这是好的写法 if(object.hasOwnProperty('related')){ …… } //如果你不确定是否为DOM对象,则这样写是好的 if('hasOwnProperty' in object && object.hasOwnProperty('related')){ …… } 因为IE浏览器存在此问题,在判断实例对象是否存在时,我更倾向于使用 in运算符,只有在需要判断实例属性时才会用到hasOwnProperty()。

看完之后,记得多提意见,共同进步……三克油!

参考资料:

《编写可维护的JavaScript》

http://www.365mini.com/page/javascript-hasownproperty.htm

http://www.jb51.net/article/20236.htm

http://blog.sina.com.cn/s/blog_54d1f65b0101dfv3.html