rob*_*ing 17 javascript arrays model backbone.js
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']
Run Code Online (Sandbox Code Playgroud)
在此示例代码中,我们有:
children_array = this.get("children")
我以为这只会指向内存中的相同数组(因此也是O(1)).然而,我认为这将是一个设计层,因为可以在不使用this.set()的情况下操纵数组,然后事件监听器就不会触发.
所以我猜它(不知何故神奇地)复制数组?
http://backbonejs.org/#Model-set
怎么了?
编辑:我刚刚在https://github.com/documentcloud/backbone/blob/master/backbone.js的骨干源代码中找到了实现(我在底部粘贴了相关代码)
获得回报:
return this.attributes[attr]
Run Code Online (Sandbox Code Playgroud)
所以这只会指向内存中的相同数组吗?所以可以在不使用set()的情况下更改数组,这样会很糟糕......?我对么?
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;
},
Run Code Online (Sandbox Code Playgroud)
mu *_*ort 32
记录的界面实际上并没有指定谁拥有数组引用,所以你自己就在这里.如果你看一下实现,你会看到(正如你所做的那样)get直接从模型的内部返回一个引用attributes.这对于不可变类型(例如数字,字符串和布尔值)都可以正常工作,但是遇到了诸如数组之类的可变类型的问题:您可以轻松地更改某些内容,而无需Backbone知道它.
骨干模型似乎旨在包含原始类型.
有三个理由要求set:
set,则不会触发事件.set,你将绕过有的验证逻辑set.如果您正在处理数组和对象值,则必须小心.
请注意,这种行为get和set是一个实现细节,未来的版本可能会更聪明地处理它们如何处理非原始属性值.
数组属性(以及对象属性)的情况实际上比您最初怀疑的要糟糕.当你说m.set(p, v),如果拔出一个数组,Backbone将不会认为这set是一个改变v === current_value_of_p:
var a = m.get(p);
Run Code Online (Sandbox Code Playgroud)
然后修改它:
a.push(x);
Run Code Online (Sandbox Code Playgroud)
并将其发回:
m.set(p, a);
Run Code Online (Sandbox Code Playgroud)
你不会"change"从模型中得到一个事件,因为a === a; Backbone 实际上使用了 Underscore isEqual,!==但在这种情况下效果是一样的.
例如,这个简单的chicanery:
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);?
Run Code Online (Sandbox Code Playgroud)
产生两个"change"事件:一个在第set一个之后,一个在最后一个之后set.
演示:http://jsfiddle.net/ambiguous/QwZDv/
如果你看一下set你会注意到对Backbone.Models 属性有一些特殊处理.
这里的基本教训很简单:
如果您打算使用可变类型作为属性值,那么如果您有可能更改该值,那么
_.clone它们将在出路(或者$.extend(true, ...)如果您需要深层复制时使用).
| 归档时间: |
|
| 查看次数: |
6293 次 |
| 最近记录: |