从数组中删除项会导致Uncaught TypeError

时间:2012-11-21 11:16:12

标签: javascript json

我有一些jQuery插件 - 所有解析JSON提要并使用Mustache.js渲染它们;每个插件都会显示要显示的项目的整数值。

尝试使用以下代码解析Stack Overflow JSON Feed时收到了Uncaught TypeError: Cannot read property 'link' of undefined

   $.ajax({
      type: 'GET',
      url: query,
      contentType: "jsonp",
      dataType: 'jsonp',
      success: function (jsonp) {

        /* loop through JSON items converting the time from UNIX timestamp
         ** format to readable words by parsing it through timeConverter() */
        var i;
        for (i = 0; i < jsonp.items.length; i++) {
          if (i > num-1){
            delete jsonp.items[i];
          } else {
            jsonp.items[i].creation_date = timeConverter(jsonp.items[i].creation_date);
          }
        }


        var output = Mustache.render(must_template, jsonp);
        element.html(output);
        return element;
      } //EOF CALLBACK
    }); //EOF AJAX

作为quickfix,我通过简单地注释掉delete操作来禁用截断。该错误表明Mustache.js正在尝试访问不再存在的JSON对象的一部分;但delete操作显然只会影响超出用户定义限制的项目。

发生此行为时,数组中仍有20个项目。

注意: 是的,我自己已经回答了这个问题;然而 - 如果它表现出最佳实践,更简洁的方式或以某种方式改善我的答案,我更愿意接受另一个答案。 :)

3 个答案:

答案 0 :(得分:1)

经过大量的谷歌搜索后,我找不到任何东西,甚至StackOverflow都让我失望了。然后,偶然的机会,我偶然发现了我的'快速黑客'的意外副作用,评论了删除行..

http://i50.tinypic.com/2ecgnxz.png http://i50.tinypic.com/2ecgnxz.png

由于我没有注释掉整个if/else块,我的timeConverter()函数没有在通常被删除的项目上运行。这证实了for()if(){} / else{}的组合正常运作。所以好像Mustache.js试图访问已被删除的项目!几乎就像删除项目时length数组的items[]属性没有更新一样。

我做了一个jsFiddle测试用例,这证实了这个问题。这是代码和输出:

    $.ajax({
      type: 'GET',
      url: query,
      contentType: "jsonp",
      dataType: 'jsonp',
      success: function (jsonp) {

        /* loop through JSON items converting the time from UNIX timestamp
         ** format to readable words by parsing it through timeConverter() */
        var i;
        for (i = 0; i < jsonp.items.length; i++) {
          if (i > num-1){
              console.log("Deleting item. Current Count: "+jsonp.items.length);
            delete jsonp.items[i];
              console.log("Deleting item. New Count: "+jsonp.items.length);
          } else {
            jsonp.items[i].creation_date = timeConverter(jsonp.items[i].creation_date);
          }
        }
        console.log(jsonp);
        return element;
      } //EOF CALLBACK
    }); //EOF AJAX

http://i45.tinypic.com/546kgj.png http://i45.tinypic.com/546kgj.png

我尝试使用计数器快速修复计数每个删除,然后从length属性(jsFiddle)中减去删除计数器:

        $.ajax({
          type: 'GET',
          url: query,
          contentType: "jsonp",
          dataType: 'jsonp',
          success: function (jsonp) {

            /* loop through JSON items converting the time from UNIX timestamp
             ** format to readable words by parsing it through timeConverter() */
            var i, deleted = 0;
            for (i = 0; i < jsonp.items.length; i++) {
              if (i > num-1){
                delete jsonp.items[i];
                deleted++;
              } else {
                jsonp.items[i].creation_date = timeConverter(jsonp.items[i].creation_date);
              }
            }
            jsonp.items.length -= deleted;
            console.log(jsonp);
            return element;
          } //EOF CALLBACK
        }); //EOF AJAX

以下是生成的输出:

http://i45.tinypic.com/vg69vo.png http://i45.tinypic.com/vg69vo.png

此代码在放回测试环境并与Mustache.js一起使用时运行正常。 使用delete关键字在数组上使用时不会影响length属性

来自Java背景我理所当然地认为length是属性而不是函数 - 因此在对数组进行任何更改时不会更新。一个愚蠢的错误让我花费的时间比应该花的多!但是,我找不到任何关于此的帖子,所以我想我会发布它,希望它能帮助其他类似职位的人!

答案 1 :(得分:1)

与数组相比,

delete是一个“低级”运算符。它直接删除对象属性,绕过所有特定的数组逻辑,因此不会更新数组的长度。

如果要从数组中删除元素,请使用.splice [MDN],或者在您的情况下,您只需设置数组的长度,然后迭代剩余的元素

jsonp.items.length = Math.min(num, jsonp.items.length);
for (i = 0; i < jsonp.items.length; i++) {
  jsonp.items[i].creation_date = timeConverter(jsonp.items[i].creation_date);
}

答案 2 :(得分:1)

删除不会改变您已经发现的数组计数,它只是删除密钥。要从数组中删除项目,您可以使用splice。例如:

var array2 = [ 1, 2, 3, 4 ];
array2.splice(2, 1);

console.log('---------------------------');
console.log(array2.length); // 3
console.log(array2[0]); // 1
console.log(array2[1]); // 2
console.log(array2[2]); // 4
console.log(array2[3]); // undefined

工作样本:http://jsfiddle.net/qbXjp/1/