• Javascript类型检测


    开门见山,我们先来看一下代码:

    var is = function (obj,type) {  
    	var toString = Object.prototype.toString;  
    	var _baseTypes = {'undefined':'undefined','number':'number','boolean':'boolean','string':'string'};
    	return (_baseTypes[typeof obj]===type)||
    	         (type === "Null" && obj === null) || 
    	         (type==='Function'&&"object" === typeof document.getElementById ?
    	         /^\s*\bfunction\b/.test("" + obj):toString.call(obj).slice(8,-1) === type)||
    	         obj instanceof type;  
    }; 

    在讲解这个函数之前,让我们先来看一下javascript类型判断的几个关键:

    typeof

    typeof运算符,用于判断一个或值是哪种类型的。

    由于Javascript语言的灵性性与执行环境的复杂性,typeof运算符并不能正确判断出所有的类型。但对于基本数据类型,typeof具有神奇的功效,正如在 is 函数中看到的那样,_baseTypes变量中定义了typeof可以正确识别的基本数据类型列表,其中键为类型名称,值为typeof运算结果。

    instanceof

    instanceof可以检测某个对象是不是另一个对象的实例。

      new String('abc') instanceof String //true

    instanceof还可以检测父类型。 

    function Animal() {};
    function Pig() {};
    Pig.prototype = new Animal();
    alert(new Pig() instanceof Animal); // true
    
    

    可以看出,instanceof不适合用来检测一个对象本身的类型。

    Constructor

    所有对象都拥有一个constructor属性,它指向该对象的构造函数。

    对于复合数据类型,我们可以采用如下方式进行检测:

    isArray: function(arr) {
       return !!arr && arr.constructor == Array;
    }
    
    

    但是比较悲剧的是这种行为并不是确定的,在一些极其特殊的情况下,会产生意外的结果:

     
    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 instanceof Array); //false
    
    

    

     下面是Johg Resig 《pro javacript Techniques》书中的一张列表:

    Duck Typing 

     在犀牛书里,提到一句老话:"如果走路像鸭子,叫声像鸭子,那他就是鸭子"。换而言之,对于Array来说,如果一个对象有splice和join属性,那它就是一个Array:

    function isArray(o) {
        return o != null && typeof o === ‘object’ &&
               'splice' in o && 'join' in o;
    }
    
    

    显然,鸭子检测很容易误把自造的天鹅也当成鸭子:

    alert(isArray({'splice': '', 'join': ''})); // true
    
    

    注:buck typing并不关注于类型,它关注的是行为,它是实际作用是相互之间约定一种行为接口,好实现类似于多态的调用

    Object.toString

     ECMA-262中的解释:

    Object.prototype.toString()

    when the toString method is called,the following steps are taken:

    1.get the [[Class]] property of this object  //得到内部属性[[Class]]

    2.conpute a string value by concatenating the three strings "[object",Result(1),and"]" //构造一个字符串类型似于[object xxx]

    3.return results(2) //返回第2条的执行结果

    注:[[Class]]为对象的内部属性,无法真接访问到

    这样,就有了:

    function isArray(o) {
        return Object.prototype.toString.call(o) === '[object Array]';
    }
    
    

    因为是字符串比较,也就解决了环境问题和语法灵活性所带来的变化,因此比较稳定。

    好,讲到现在,想必大家对javascript类型判断应该有一个较为深入的理解,我想通过自已的能力,应该也可以写一个比较完善的类型判断函数,那下面就来看一下我是如何实现的。

    var is = function (obj,type) {  
    	var toString = Object.prototype.toString;  
    	var _baseTypes = {'undefined':'undefined','number':'number','boolean':'boolean','string':'string'};
    	return (_baseTypes[typeof obj]===type)||
    	         (type === "Null" && obj === null) || 
    	         (type==='Function'&&"object" === typeof document.getElementById ?
    	         /^\s*\bfunction\b/.test("" + obj):toString.call(obj).slice(8,-1) === type)||
    	         obj instanceof type;  
    }; 
    

    因为考虑到实用性,这里是通过传入对象obj和期望类型type,返回boolean值,true为obj为type类型,false为obj不为type类型来实现的.

    首先,var toString = Object.prototype.toString;这里保存了一份对Object的原生toString方法的引用,方便后面使用

       var _baseTypes = {'undefined':'undefined','number':'number','boolean':'boolean','string':'string'};

       这里保存了一份对于typeof可以检测出来的基本数据类型的对象列表,其键类型名称,值为typeof该类型的结果。

    然后:进行类型的检测,返回结果。

       (_baseTypes[typeof obj] === type) :检测是否为基本数据类型

            (type === 'Null' && obj === null):

        因为null实际上属于Object类型,因此typeof null 和Object.prototype.toString(null)返回的结果都为object和[Object object]

        在实际需求中,我们通常希望将null单独列出来作为一种类型来进行判断

        (type==='function'&&'object'===typeof document.getElementById?/^\s*\bfunction\b/.test(""+obj):toString.call(obj).slice(8,-1)===type)

              这里实际上是在判断obj是否是一个函数,而IE6存在bug,无法正确识别getElementById这类函数,因此做了上些特殊的处理。

       obj instanceof type:判断obj是否为type的实例

       这里主要是来处理一引起特殊情况,如一些自定义对象的问题。

        

    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
    
    

    好,并不多了,最后我们来看一个测试结果:

    代码
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <title>typecheck.html</title>

    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
    <script type="text/javascript">
    var is = function (obj,type) {
    var toString = Object.prototype.toString;
    var _baseTypes = {'undefined':'undefined','number':'number','boolean':'boolean','string':'string'};
    return (_baseTypes[typeof obj]===type)||
    (type
    === "Null" && obj === null) ||
    (type
    ==='Function'&&"object" === typeof document.getElementById ?
    /^\s*\bfunction\b/.test("" + obj):toString.call(obj).slice(8,-1) === type)||
    obj
    instanceof type;
    };

    window.onload
    = function(){
    var msg = document.getElementById("msg");
    function addMsg(m){
    msg.innerHTML
    +=m+"<br />";
    }

    //判断基本数据类型
    addMsg("1,number"+":"+is(1,'number'));
    addMsg(
    "abc,string"+":"+is("abc","string"));
    addMsg(
    "true,boolean"+":"+is(true,"boolean"));
    addMsg(
    "undefined,undefined"+":"+is(undefined,'undefined'));
    //判断引用数据类型
    addMsg("null,Null"+":"+is(null,"Null"));
    addMsg(
    "new String(''),String"+":"+is(new String(""),"String"));
    addMsg(
    "{},Object"+":"+is({},"Object"));
    addMsg(
    "[],Array"+":"+is([],"Array"));
    addMsg(
    "/foo/,RegExp"+":"+is(/foo/,"RegExp"));
    try {0()} catch (e) {
    addMsg(
    "try/catch(e),Error"+":"+is(e,"Error"));
    }
    addMsg(
    "new Date(),Date"+":"+is(new Date(),"Date"));
    addMsg(
    "new Number(123),Number"+":"+is(new Number(123),"Number"));
    addMsg(
    "new Boolean(true),Boolean"+":"+is(new Boolean(true),"Boolean"));
    addMsg(
    "function(){},Function"+":"+is(function(){},"Function"));

    function SubArray() {}
    SubArray.prototype
    = [];
    addMsg(
    "SubArray,Array"+":"+is(new SubArray(),Array));
    }

    </script>
    </head>

    <body>
    <div id="msg"></div>
    </body>
    </html>

    兼容判断类型列表:

    基本数据类型 undefined,string,number,boolean

    复合数据类型 Date,String,Boolean,Number,Object,Function,Array,RegExp,Error

    其他 instanceof 的范畴

    参考:

    

    http://lifesinger.org/blog/2009/02/javascript-type-check-1/
    http://www.planabc.net/2010/01/23/repair_the_bug_of_isfunction_method_in_jquery/
    

     体会:

    悲剧啊,第一次写博,没想到要花这么多精力

    悲剧啊,参考永远是中文,估计水平也高不到哪里去,唉,英文不行,怎么办呢!

  • 相关阅读:
    【shell】两种字符串提取场景的实现
    【batch】批处理文件多参数处理和for循环字符串连接
    【Java】「深入理解Java虚拟机」学习笔记(4)- 类文件结构
    【Java】「深入理解Java虚拟机」学习笔记(2)- JVM内存区域
    【Java】「深入理解Java虚拟机」学习笔记(1)
    【Myeclipse】用Myeclipse10.5搭建C/C++开发环境
    【JDK】JDK模块化(1)-为什么要模块化
    【DOS】文件统计命令
    【java】转:Windows系统下面多个jdk版本切换
    【Web】servlet、filter和listener
  • 原文地址:https://www.cnblogs.com/fool/p/javascrpt.html
Copyright © 2020-2023  润新知