清除 Backbone 模型中除一个属性之外的所有属性

Clear all attributes except one on a Backbone Model

我有一个模型,其属性比默认属性多。我需要在 guest 更改时清除所有属性并设置回默认值,这样我就不会携带不必要的属性。

由于 change:guest 事件,清除所有属性并设置回默认值会导致无限循环。

如何删除除一个属性之外的所有属性?
当模型属性设置回默认值时,有没有办法不触发另一个更改事件?
或者删除默认值中未列出的任何内容?

这是我的模特

defaults: {
  _id: 'id',
  first_name: 'first_name',
  last_name: 'last_name',
  guest: true
}

我听'guest'改变事件

this.on('change:guest', this.reset);

更改事件调用 reset 来更新模型,显然这会导致无限循环。

reset: function() {
  var new_defaults = _.clone(this.defaults);
  this.clear({silent: true});
  this.set(new_defaults);
}

I have made a reset function that you can easily add to a base Backbone model. I go into more details about this solution into another answer.

它比简单的 .clear followed by a .set because it merges the defaults 返回模型更好,让任何传递的 attributes 像初始化时一样覆盖它们。

/**
 * Clears the model's attributes and sets the default attributes.
 * @param {Object} attributes to overwrite defaults
 * @param {Object} options to pass with the "set" call.
 * @return {Backbone.Model} this object, to chain function calls.
 */
reset: function(attributes, options) {
    options = _.extend({ reset: true }, options);

    // ensure default params
    var defaults = _.result(this, 'defaults'),
        attrs = _.defaults(_.extend({}, defaults, attributes || {}), defaults);

    // apply
    this._reset(attrs, options);

    // triggers a custom event, namespaced to model in order
    // to avoid collision with collection's native reset event
    // when listening to a collection.
    if (!options.silent) this.trigger('model:reset', this, options);

    return this;
},

/**
 * Private method to help wrap reset with a custom behavior in child
 * classes.
 * @param {Object} attributes to overwrite defaults
 * @param {Object} options to pass with the "set" call.
 */
_reset: function(attrs, options) {
    this.clear({ silent: true }).set(attrs, options);
},

那么你的模型:

var MyModel = BaseModel.extend({
    idAttribute: '_id',
    defaults: {
        first_name: 'first_name',
        last_name: 'last_name',
        guest: true
    },
    initialize: function() {
        this.listenTo(this, 'change:guest', this.onGuestChange);
    },
    onGuestChange: function(model, value, options) {
        this.reset(null, { silent: true });
    }
});

这样,当 guestonGuestChange 处理程序发生变化时,您可以更灵活地处理,这使得您可以随心所欲地调用 reset,这里使用 { silent: true }选项。

概念验证

var BaseModel = Backbone.Model.extend({
  /**
   * Clears the model's attributes and sets the default attributes.
   * @param {Object} attributes to overwrite defaults
   * @param {Object} options  to pass with the "set" call.
   * @return {Backbone.Model}  this object, to chain function calls.
   */
  reset: function(attributes, options) {
    options = _.extend({
      reset: true
    }, options);

    // ensure default params
    var defaults = _.result(this, 'defaults'),
      attrs = _.defaults(_.extend({}, defaults, attributes || {}), defaults);

    // apply
    this._reset(attrs, options);

    // triggers a custom event, namespaced to model in order
    // to avoid collision with collection's native reset event
    // when listening to a collection.
    if (!options.silent) this.trigger('model:reset', this, options);

    return this;
  },

  /**
   * Private method to help wrap reset with a custom behavior in child
   * classes.
   * @param  {Object} attributes to overwrite defaults
   * @param  {Object} options  to pass with the "set" call.
   */
  _reset: function(attrs, options) {
    this.clear({
      silent: true
    }).set(attrs, options);
  },
})


var MyModel = BaseModel.extend({
  defaults: {
    first_name: 'first_name',
    last_name: 'last_name',
    guest: true
  },
  initialize: function() {
    this.listenTo(this, 'change:guest', this.onGuestChange);
  },
  onGuestChange: function(model, value, options) {
    this.reset(null, {
      silent: true
    });
  }
});

var model = new MyModel({
  first_name: 'test',
});
console.log('before:', model.attributes);
model.set('guest', false);

console.log('after:', model.attributes);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>


您无需克隆默认值即可使用它们。如果它们有数组或嵌套对象,defaults 应该是一个返回对象的函数。

defaults: function() {
    return {
        arr: [],
        nested: { prop: 'test' }
    };
},

然后,使用_.result to call the defaults: _.result(this, 'defaults') like in my reset function. The Backbone documentation on defaults有这个通知:

Remember that in JavaScript, objects are passed by reference, so if you include an object as a default value, it will be shared among all instances. Instead, define defaults as a function.