不Backbone.Models this.get()整个阵列或点复制到存储器中的相同阵列(does

2019-06-26 12:45发布

 Person = Backbone.Model.extend({
        defaults: {
            name: 'Fetus',
            age: 0,
            children: []
        },
        initialize: function(){
            alert("Welcome to this world");
        },
        adopt: function( newChildsName ){
            var children_array = this.get("children");
            children_array.push( newChildsName );
            this.set({ children: children_array });
        }
    });

    var person = new Person({ name: "Thomas", age: 67, children: ['Ryan']});
    person.adopt('John Resig');
    var children = person.get("children"); // ['Ryan', 'John Resig']

在这个例子中的代码,我们有:

children_array = this.get( “孩子”)

我想这将只是指向同一阵列中的存储器(因此是O(1))。 不过转念一想,这将是一个设计地板,因为一个可以操纵的阵列,而无需使用this.set(),然后事件监听器就不会开火。

所以我猜它(不知何故神奇地)副本的阵列?

http://backbonejs.org/#Model-set

怎么了?

编辑:我刚刚发现的骨干源代码执行情况https://github.com/documentcloud/backbone/blob/master/backbone.js (我已经贴在底部的相关代码)

获取收益:

return this.attributes[attr]

所以这将只是指向内存中右同一阵列? 因此,人们可以改变不使用一套(数组),这将是坏..? 我对么?

get: function(attr) {
      return this.attributes[attr];
    },

    // Get the HTML-escaped value of an attribute.
    escape: function(attr) {
      var html;
      if (html = this._escapedAttributes[attr]) return html;
      var val = this.get(attr);
      return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val);
    },

    // Returns `true` if the attribute contains a value that is not null
    // or undefined.
    has: function(attr) {
      return this.get(attr) != null;
    },

    // Set a hash of model attributes on the object, firing `"change"` unless
    // you choose to silence it.
    set: function(key, value, options) {
      var attrs, attr, val;

      // Handle both `"key", value` and `{key: value}` -style arguments.
      if (_.isObject(key) || key == null) {
        attrs = key;
        options = value;
      } else {
        attrs = {};
        attrs[key] = value;
      }

      // Extract attributes and options.
      options || (options = {});
      if (!attrs) return this;
      if (attrs instanceof Model) attrs = attrs.attributes;
      if (options.unset) for (attr in attrs) attrs[attr] = void 0;

      // Run validation.
      if (!this._validate(attrs, options)) return false;

      // Check for changes of `id`.
      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];

      var changes = options.changes = {};
      var now = this.attributes;
      var escaped = this._escapedAttributes;
      var prev = this._previousAttributes || {};

      // For each `set` attribute...
      for (attr in attrs) {
        val = attrs[attr];

        // If the new and current value differ, record the change.
        if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
          delete escaped[attr];
          (options.silent ? this._silent : changes)[attr] = true;
        }

        // Update or delete the current value.
        options.unset ? delete now[attr] : now[attr] = val;

        // If the new and previous value differ, record the change.  If not,
        // then remove changes for this attribute.
        if (!_.isEqual(prev[attr], val) || (_.has(now, attr) !== _.has(prev, attr))) {
          this.changed[attr] = val;
          if (!options.silent) this._pending[attr] = true;
        } else {
          delete this.changed[attr];
          delete this._pending[attr];
        }
      }

      // Fire the `"change"` events.
      if (!options.silent) this.change(options);
      return this;
    },

Answer 1:

该公开的接口实际上并不指定谁拥有数组引用,所以你是你自己在这里。 如果你看一下实现,你会看到(如你所做的)这get刚刚返回直出模型内部的参考attributes 。 这正常工作与不变类型(如数字,字符串和布尔值),但运行到与可变类型的问题,如数组:你可以很容易改变的东西,而不必骨干知道关于它的任何方式。

骨干机型似乎旨在包含基本类型。

原因有三调用set

  1. 这就是接口规范说的事情。
  2. 如果你不叫set ,你不触发事件。
  3. 如果你不叫set ,你会绕过验证逻辑set了。

你只需要,如果你用数组和对象值的工作要小心。

请注意,这种行为getset是一个实现细节和未来的版本中可能会得到关于他们如何处理非原始属性值更聪明。


与阵列的情况属性(以及与此有关的对象属性)实际上是比你差可能最初怀疑。 当你说m.set(p, v)骨干网将不考虑set如果要改变v === current_value_of_p所以如果你拉出一个数组:

var a = m.get(p);

然后修改它:

a.push(x);

并将其发回的:

m.set(p, a);

你不会得到一个"change"从模型事件,因为a === a ; 骨干实际使用下划线的isEqual结合!==但效果是在这种情况下是相同的。

例如,诈骗的这个简单的一点:

var M = Backbone.Model.extend({});
var m = new M({ p: [ 1 ] });
m.on('change', function() { console.log('changed') });

console.log('Set to new array');
m.set('p', [2]);

console.log('Change without set');
m.get('p').push(3);

console.log('Get array, change, and re-set it');
var a = m.get('p'); a.push(4); m.set('p', a);

console.log('Get array, clone it, change it, set it');
a = _(m.get('p')).clone(); a.push(5); m.set('p', a);​

产生两个"change"事件:一个后第一set和一个最后的后set

演示: http://jsfiddle.net/ambiguous/QwZDv/

如果你看一下set ,你会发现,有对于那些属性一些特殊的处理Backbone.Model秒。


这里的基本教训很简单:

如果你要使用可变类型的属性值, _.clone他们的出路(或使用$.extend(true, ...)如果你需要一个深层副本)如果有任何机会,你会改变数值。



文章来源: does Backbone.Models this.get() copy an entire array or point to the same array in memory