骨干视图collection.each()bug?

时间:2014-04-15 11:25:13

标签: javascript backbone.js underscore.js

这个应该很简单,但事实并非如此,这让我很头疼。

我复制/粘贴了一个相当简单的“Hello Backbone”代码,并对其进行了简化,以获得此代码:

(function($){
  var Item = Backbone.Model.extend({
    defaults: {
      part1: 'hello',
      part2: 'world'
    },

    initialize: function() {
      //console.log("initialize item");
    }
  });

  var List = Backbone.Collection.extend({
    model: Item,

    initialize: function() {
      //console.log("initialize list");
    }
  });

  var ListView = Backbone.View.extend({
    //el: $('body'), // el attaches to existing element

    initialize: function(){
      _.bindAll(this, 'render'); // every function that uses 'this' as the current object should be in here

      this.collection = new List();

      this.render();
    },
    render: function(){
      //console.log("listview render");
    },
  });

  var listView = new ListView();

  var item1 = new Item();
  listView.collection.add(item1);

  console.dir("Emptying collection...");
  listView.collection.each(function (item) {
    console.dir("Removing model cid:" + item.cid);
    listView.collection.remove(item);
  })

  var item2 = new Item();
  listView.collection.add(item2);

  var item3 = new Item();
  listView.collection.add(item3);

  console.dir("Emptying collection...");
  listView.collection.each(function (item) {
    console.dir("Removing model cid:" + item.cid);
    listView.collection.remove(item);
  })

  console.log(listView.collection.length);
})(jQuery);

第一部分实际上是一些骨干样板文件,最后一部分应该是:

  • 将模型添加到集合
  • 清晰收藏
  • 将两个模型添加到集合
  • 清晰收藏

最后,listView.collection.length应为0,但事实并非如此。 剩下一个型号。

我从控制台日志中看到,listView.collection.each(function (item) { ... })没有做它应该做的事情,因为在第二次集合迭代中只删除一个项,而不是两个项目。

所以,我做错了什么或者某处有错误?

更新:这是jsfiddle

2 个答案:

答案 0 :(得分:1)

您在迭代时会改变元素列表(listView.collection.remove(item)),这通常会导致Bad Things™这是一个简化的测试用例:http://jsfiddle.net/nikoshr/Xx9uw/

在删除之前克隆模型列表:

_.each(_.clone(listView.collection.models), function (item) {
    console.log("Removing model cid:" + item.cid);
    listView.collection.remove(item);
});

http://jsfiddle.net/nikoshr/Xx9uw/2/

或使用collection.reset

listView.collection.reset();

http://jsfiddle.net/nikoshr/Xx9uw/3/

答案 1 :(得分:0)

当我看到@ nikoshr的回答时,我知道我是个傻瓜。再次。我在不同的语言中重复同样的错误,C / C ++(通常会产生ye-olde-segfault),Java,C#等......现在JS / BB。

该死。

除了nikoshr的答案之外,我发现这个基于集合的解决方案可以避免经典迭代(在C#中可以使用linq扩展来实现这一目的):

this.collection
  .forEach(function (item) {
    item.destroy()
  });

方便的是,Underscore为您提供了过滤掉您真正需要的模型的选项:

this.collection
  .where({ YourAttribute: YourValue, YourOtherAttribute: YourOtherValue })
  .forEach(function (item) {
    item.destroy()
  });