• javascript中对数组的判定浅析


    这是司徒正美收集的js判断是否是数组的方法:

    http://www.cnblogs.com/rubylouvre/archive/2009/09/15/1567338.html

    Douglas Crockford的版本

    var isArray = function(a){
      return a &&
        typeof a === 'object' &&
        typeof a.length === 'number' &&
        typeof a.splice === 'function' &&
        !(a.propertyIsEnumerable('length'));
    }

    Ext与JQuery的版本

    var isArray = function(v){
      return Object.prototype.toString.apply(v) === '[object Array]';
    }

    Prototype的版本

    var isArray = function(object) {
      return object != null && typeof object === "object" &&
        'splice' in object && 'join' in object;
    }

    1、道格拉斯的方法最后一个a.propertyIsEnumerable('length')是一个函数,返回布尔值,该值指示指定属性是否为对象的一部分以及该属性是否是可枚举的。如果 length 存在于 object 中且可以使用一个 For...In 循环枚举出来,则 propertyIsEnumerable 属性将返回 true。如果 object 不具有所指定名称的属性或者所指定的属性不是可枚举的,则propertyIsEnumerable 属性将返回 false。通常,预定义的属性不是可枚举的,而用户定义的属性总是可枚举的。如果a是一个数组,则属性length是不可枚举的,所以返回false,!a.propertyIsEnumerable('length')将返回true,表示是数组。道格拉斯的判断方法即是说如果一个对象有长度属性,有splice方法,并且长度属性是预定义属性而不是用户自定义属性,则a是数组。

    2、jquery方法,这个方法很精妙,很多地方都用到了。但是我实在是不太明白为什么这样可以判断是不是一个数组。分析如下:

    先来看看toString这个方法吧:JavaScript中toString函数方法是返回对象的字符串表示。使用方法:

    objectname. toString([radix])

    其中objectname是必选项。要得到字符串表示的对象。radix是可选项。指定将数字值转换为字符串时的进制。JavaScript中toString函数方法是所有内建的 JScript 对象的成员。它的操作依赖于对象的类型:

    对象 操作
    Array 将 Array 的元素转换为字符串。结果字符串由逗号分隔,且连接起来。
    Boolean 如果 Boolean 值是 true,则返回 “true”。否则,返回 “false”。
    Date 返回日期的文字表示法。
    Error 返回一个包含相关错误消息的字符串。
    Function 返回如下格式的字符串,其中 functionname 是被调用 toString 方法函数的名称: function functionname( ) { [native code] }
    Number 返回数字的文字表示。
    String 返回 String 对象的值。
    默认 返回 “[object objectname]”,其中 objectname 是对象类型的名称。

    也就是说一个数组执行toString()方法后,返回的是一个有逗号分隔的字符串。var x=[];x.constructor.prototype.toString()等于"";但是Object.prototype.toString()这样用又是什么意思咧?看这篇文章:

    http://blog.csdn.net/zhangw428/article/details/4171630

    为什么要用Object.prototype.toString而不是Function.prototype.toString或者其它?这是和他们的toString解释方式有关系的。下面是ECMA中对Object.prototype.toString的解释:其过程简单说来就是:1、获取对象的类名(对象类型)。2、然后将[object、获取的类名、]组合并返回。

    ECMA中对Array有如下说明:

    The [[Class]] property of the newly constructed object is set to “Array”.

    因此我们用如下代码来检测数组:

    function isArray(o) {
      return Object.prototype.toString.call(o) === '[object Array]';  
    }
    这种方式既解决了instanceof存在的跨页面问题,也解决了属性检测方式所存在的问题,实在是一种妙招,一个很好的解决方案。除此之外,这种解决办法也可以应用于判断Date,Function等类型的对象。所以可以扩展判断很多类型的函数。

    var is = 
    { 
    types : ["Array", "Boolean", "Date", "Number", "Object", "RegExp", "String", "Window", "HTMLDocument"] 
    } 
    
    for(var i = 0, c; c = is.types[i ++ ]; ) { 
        is[c] = (function(type) { 
              return function(obj) { 
                     return Object.prototype.toString.call(obj) == "[object " + type + "]"; 
              } 
         } )(c); 
    } 
    alert(is.Array([])); // true 
    alert(is.Date(new Date)); // true 
    alert(is.RegExp(/reg/ig)); // true 

    这里说下中间有个is[c]。js中object.name 和object['name']是等价的。但是.存取属性的操作符操作的只能是标识符,而[]操作符操作的可以是变量,字符串或直接量(如1)。

    所以这里只能用[]的方法。
    3、prototype的方法:

    一个非空对象存在splice和join方法就是数组。不过这个方式是有问题的,因为没有判断splice和join方式是不是对象的预定义属性。比如var o = {splice:true,join:true}
    isArray(o),这样,判断为true,但实际上他不是数组。修改为:

    var isArray = function(object) {
      return object != null && typeof object === "object" &&
        'splice' in object && 'join' in object&&!(object.propertyIsEnumerable('splice'))&&!(object.propertyIsEnumerable('join'));
    }

    4、再来说说最常用到的方法:

    var arr = [];
    arr instanceof Array; // true
    arr.constructor == Array; //true

    typeof arr 方法显然不行,他会返回"object",那instanceof行不行了,正常情况下是行的,如果 object 是 class 或构造函数的实例,则 instanceof 运算符返回 true。如果 object 不是指定类或函数的实例,或者 object 为 null,则返回 false。如: 
    [] instanceof Array; // true 
    [] instanceof Object; // true 
    [] instanceof RegExp; // false 
    new Date instanceof Date; // true 
    所以,可以用instanceof运算符来判断对象是否为数组类型: 

    function isArray(arr) 
    { 
     return arr instanceof Array; 
    } 

    JavaScript中,每个对象都有一个constructor属性,它引用了初始化该对象的构造函数,常用于判断未知对象的类型。如给定一个求知的值通过typeof运算符来判断它是原始的值还是对象。如果是对象,就可以使用constructor属性来判断其类型。所以判断数组的函数也可以这样写: 

    function isArray(arr) 
    { 
    return typeof arr == "object" && arr.constructor == Array; 
    } 

    很多情况下,我们可以使用instanceof运算符或对象的constructor属性来检测对象是否为数组。

    刚刚说了,正常情况下可以,说明特殊情况下是不行的,那么什么是特殊情况咧?

    <script> 
    window.onload=function(){ 
        var iframe_arr=new window.frames[0].Array; 
        alert(iframe_arr instanceof Array); // false 
        alert(iframe_arr.constructor == Array); // false 
    } 
    </script> 
    
    <body> 
    <iframe></iframe> 
    </body> 

    这个例子是晚上的,结果是对的,说明检查跨框架(cross-frame)页面中的数组时,会失败,原因就是在不同框架(iframe)中创建的数组不会相互共享其prototype属性。

    但是我自己写了两个页面测试的时候,又可以,这里希望有高手指点:

    <html>
    <body>
    <script type="text/javascript">
    
    function f(v){
        alert(v instanceof Array)
    }
    f([]);//true
    
    </script>
    <iframe src="2.html"></iframe>
    </body>
    </html>

    iframe页面如下:

    <html>
    <body>
    testshare
    <script type="text/javascript">
    
    function xxx(){
        top.parent.f([])
    }
    </script>
    <input type = "button" onclick="xxx()"/>
    </body>
    </html>

    会报错,这里在继续测试。

    参考文献:

    http://sofish.de/1591

    http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

     

     

     

     

     

  • 相关阅读:
    ubuntu 12.04(Precise Pangolin)启用休眠(Hibernate)功能的方案
    svn小技巧——重定向svn diff
    引用对象深度复制
    引用对象深度复制的简单实现方法
    vue Excel导出 [post请求+提示语]
    随手笔记-二进制的正负计算
    枚举类的扩展使用
    关于担心java import xxx.*对资源占用的一次小实践
    idea 自动添加注释 (方法+类 带参数/返回值)
    maven打包到本地仓库
  • 原文地址:https://www.cnblogs.com/fredshare/p/2651723.html
Copyright © 2020-2023  润新知