【问题标题】:Check how deep an array goes检查数组的深度
【发布时间】:2012-11-11 00:17:46
【问题描述】:

我使用$.ajax()dataType: "xml"GMail API 接收数据,然后将其扔到$.xml2json,即jQuery plugin。问题是(正如页面上的演示具有讽刺意味的那样)当我输入这样的内容时:

<animals>
     <dog>
          <name>Rufus</name>
          <breed>labrador</breed>
     </dog>
     <dog>
          <name>Marty</name>
          <breed>whippet</breed>
     </dog>
     <cat name="Matilda"/>
</animals>

我明白了:

{
    animals: {
        dog: [
            {
                name: 'Rufus',
                breed: 'labrador'
            }, {
                name: 'Marty',
                breed: 'whippet'
            }
        ],
        cat: {
            name: 'Matilda'
        }
    }
}

无论如何,如您所见,&lt;animals&gt; 中有两个&lt;dog&gt;s,只有一个&lt;cat&gt;;因此,animals["cat"] 是一个对象,而animals["dog"] 是一个对象数组。同样,当 GMail 只返回一个 &lt;entry&gt; 时,feed["entry"] 是其中包含的内容的数组,但是当有多个标签时,feed["entry"] 是一个条目数组,而这些条目又是里面有什么。

我想做的是使用条件语句做不同的事情,具体取决于我是否有 1 个或多个条目;为此,我需要一个布尔值,它告诉我有多少条目。我该怎么做呢?欢迎使用 JQuery。

编辑:我想另一个可能的答案是编辑插件本身的源代码并使其提供某种方式来知道它是一个单独的标签(一个类似数组的对象)还是有很多标签(一个“真正的”数组)。

【问题讨论】:

  • 要清楚,[] 是一个数组,{} 是一个对象。如果您相应地更改措辞,您的问题会更清楚。此外,布尔值是一个真/假值 - 您不会将它用于项目计数。
  • animals["dog"] 实际上是一个对象的数组。 /NITPICK
  • @glortho 我猜。此外,(非常烦人)在他们两个上调用typeof 似乎返回“对象”。有没有其他方法可以区分这两者?
  • @glortho - 从技术上讲,if() 中的任何内容都是布尔值;这就是我的意思:D
  • Object.prototype.toString.call( [] )Object.prototype.toString.call( {} )

标签: javascript jquery html xml json


【解决方案1】:

我认为您可以在这里做的最好的事情就是简单地将对象/数组concat 转换为一个空数组:

var obj = {a:"hello"};
[].concat(obj); // [{a:"hello"}]

var arr = [{a:"hello"}];
[].concat(arr); // identical results

所以要修复你的对象:

for ( var prop in obj ) {
    obj[prop] = [].concat(obj[prop])
}

这样你总是会得到一个数组,而不必担心你有哪一个。

【讨论】:

  • 这是一个简洁明了的技巧,甚至可能更快,但对于未来的维护者来说,它的可读性较差。
  • @zetlen 我不同意那里。标准化返回类型几乎总是让人们以后的事情变得更容易。你可以得到一个单元素数组,或者一个 500 个元素的数组,但你总是知道它是一个对象数组。
  • 我完全同意这一点!问题不在于是否对数组进行标准化,而是如何标准化!
  • 我很好奇各种数组转换的速度,so I made a JSPerfinstanceof 赢了,但不可靠,所以你的方法是最好的。你真好!
  • 由于某种原因它不起作用,即如果我有一个名为 a 的类似数组的对象,当我连接它时,a[0] 仍然不起作用。
【解决方案2】:
var json = {
    animals: {
        dog: [
            {
                name: 'Rufus',
                breed: 'labrador'
            }, {
                name: 'Marty',
                breed: 'whippet'
            }
        ],
        cat: {
            name: 'Matilda'
        }
    }
};

for ( var i in json ) {
    if ( json.hasOwnProperty( i ) ) {
        if ( json[i] instanceof Array ) {
            // you have an array, do as you please
        } else {
            // you have an object, do as you please
        }
    }
}

【讨论】:

  • 啊,但是数组的数组呢?
【解决方案3】:

您可以使用 jQuery type() 方法来简化您的代码并利用完全跨浏览器兼容的测试

API 参考:http://api.jquery.com/jQuery.type/

$.each(data, function(i, item) {

    switch($.type(item)) {
      case 'string':
        /* string code*/
        break;

      case 'array':
        /* aray code*/
        break;

        /* ....etc*/
    }
});

【讨论】:

    【解决方案4】:

    这是 xml2json 中的一个错误,更普遍的是将 XML 转换为 JSON 的问题——没有像 XSLT 或 XSD 这样的描述文档,就无法告诉序列化程序某些东西应该是一个集合。您可能想研究类似 this 的东西,以便以更正式的方式将 XML 转换为 JSON。

    同时,这里有一种方法,如果不是,则强制变量为数组,如果是,则保持不变:

    x = [].concat(x);
    

    注意:这是事后编辑的,以使用@Asad 回答中的优越方法

    正如您所观察到的,这对于多维数组开始失败,因此听起来您最好开始使用 XSLT 来描述哪些元素始终是集合。

    不要使用instanceof

    存在instanceoffails 的极端情况。像x instanceof Array 一样使用的instanceof 运算符测试原型链中是否存在特定的构造函数(在本例中为window.Array)。 但是当变量来自另一个窗口时,这会失败,例如弹出窗口或存在于同一域中并且可以将对象直接传递给其父级的 iframe。

    【讨论】:

    • 原始帖子中没有任何内容表明数据将来自另一个窗口对象。您的边缘情况几乎不会强制发出大而大胆的警告。
    • 以后我会在 Markdown 框中再输入一个#号,以符合您的意愿。
    • @glortho 实际上,当您进行跨域 AJAX 时,更常见的客厅技巧之一是使用跨域 iframe 接收器。随着浏览器变得越来越好,这种情况变得越来越少,但仍然很常见,以至于任何提及从外部端点获取 JSON 确实会强制发出这样的警告。
    • 强制发出警告,是的,但不是格式化为传达天数结束。
    猜你喜欢
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2012-01-29
    • 1970-01-01
    • 2010-12-26
    • 2012-11-11
    • 2012-09-27
    相关资源
    最近更新 更多