【问题标题】:Differentiating between arrays and "hashes" in Javascript区分 Javascript 中的数组和“哈希”
【发布时间】:2011-03-14 00:05:42
【问题描述】:

为了使我的一个函数的语法更好,我需要能够判断特定参数是数组还是“哈希”(我知道它们只是对象)。

Typeof 不起作用,因为它们都返回相同的东西

typeof {foo:"bar"} // Object

typeof ["foo","bar"] // Object

那么我该如何区分这两者呢?

我知道这可行,但我希望有更好的方法

({foo:"bar"}).constructor // Object()

(["foo","bar"]).constructor // [ undefined ]

编辑 啊,好像firebug中的[ undefined ]和Array是一样的。有点奇怪。

【问题讨论】:

    标签: javascript


    【解决方案1】:

    您可以按照 SLaks 的建议检查长度属性,但是一旦您将函数对象传递给它,您就会感到惊讶,因为它实际上具有长度属性。此外,如果对象定义了长度属性,您将再次得到错误的结果。

    你最好的选择可能是:

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

    jQuery 使用它,还有“几个”其他人...... :)

    它比 instanceof 方式更能证明失败。以下文章也建议了该方法:

    'instanceof' considered harmful (or how to write a robust 'isArray') (@kagax)

    另外补充一点,这个函数与 ES 5 规范中的 Array.isArray 函数几乎相同:

    15.4.3.2 Array.isArray(arg)

    1. 如果 Type(arg) 不是 Object,则返回 错误
    2. 如果 [[Class]] 的值 arg 的内部属性是 "Array", 然后返回 true
    3. 返回 false

    【讨论】:

    • 好文章展示了使用 iframe 时 instanceof 可能会如何失败。
    • 很多好的答案,但这看起来是最好的方法。也感谢您的参考。
    • np :) 感谢@kangax btw。我有点好奇 jQuery 是否因为这篇文章而将其代码更改为这种方法...... :)
    • 对我来说,它只有在我执行Object.prototype.toString.call(obj) 时才有效,如参考中所述。 toString.call(obj) 返回[xpconnect wrapped native prototype]
    • 这个例子是从 jQuery 中截取的,它出于某种原因将 Object.prototype.toString 放在变量 toString 中。它不会按原样工作。
    【解决方案2】:

    something instanceof Array 在单个文档中可以正常工作,但如果您开始在不同窗口之间传递数组,则会失败,因为来自一个窗口的Array 与另一个窗口上的Array 是不同的对象。如果您不打算执行跨窗口脚本(一般来说,值得避免),我建议您坚持这样做。

    如果您需要跨窗口支持,事情会稍微复杂一些。未来的故事很简单,因为 ECMAScript 第五版定义了一个函数来做到这一点:

    Array.isArray([1]);   // -> true
    

    您应该在可用的情况下使用此功能,因为它是唯一可靠且受标准认可的方式。但是,今天的许多浏览器还不支持它。

    如果它不可用,您必须依赖Object#toString 序列化,这很丑陋且有点狡猾。尽管它通常可以在当今的浏览器上可靠地工作,但在某些情况下它可能不会(主要与主机对象有关)。

    您可以在不支持它的浏览器上将此备用方法破解为Array,然后始终使用Array.isArray

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

    至于constructor,千万不要用。它并非在任何地方都可用,并且不会按照您的想法进行。使用它几乎总是一个错误。

    【讨论】:

    【解决方案3】:

    我认为最优雅的方式是简单地使用instanceof 运算符:

    if (myVar instanceof Array)
        doSomething();
    

    例子:

    [] instanceof Array           // true
    {} instanceof Array           // false
    {length:100} instanceof Array // false
    null instanceof Array         // false
    

    编辑:

    请注意,从另一个 iFrame 测试对象时它会失败(请参阅 @galambalazs 和 @bobince 的答案)

    【讨论】:

    • 同意,它处理数组子类,不能用各种属性伪造,并且不诉诸字符串比较。
    • 如果您不需要跨窗口脚本支持,这是最干净的。
    【解决方案4】:

    检查length 属性:

    "length" in {foo:"bar"}   //false
    "length" in ["foo","bar"] //true
    

    【讨论】:

    • "length in {foo:"bar", length:"baz"} // true`
    • -1 不幸的是函数对象会毁了这个,看看我的回答...... + Chadwick 说了什么
    • 我没有得到@Chadwick 的结果。据我所知,这是正确的,但被否决了。
    • 哈希(对象)可以具有length 属性,如我在上面的评论中所见。我认为@galambalazs 指的是创建一个具有length 函数的类,这将是等效的。仅仅因为一个对象有一个length 属性,并不意味着它是一个数组。
    • @Chadwick "I think @galambalazs is referring to creating a class with a length function," - 绝对不是。 :) 1.) 该语言没有类。 2.) 我说的是一个函数对象,比如function f(a){},然后试试alert(f.length),它将是一个(1)。 3.) 函数实际上是该语言中的一等对象
    【解决方案5】:

    此typeof函数用于纠正typeof运算符的数组/对象冲突,空/对象冲突。但是,它不能跨框架或跨窗口工作。查看源代码,了解适用于这些的更高级版本。

    function typeOf(value) {
        var s = typeof value;
        if (s === 'object') {
            if (value) {
                if (value instanceof Array) {
                    s = 'array';
                }
            } else {
                s = 'null';
            }
        }
        return s;
    }
    

    来源:Douglas Crockford's Javascript site

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-21
      • 1970-01-01
      • 2011-08-31
      • 2016-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多