我正在尝试在 Backbone.js 中实现我的“实例存储”版本,如 Soundcloud 在他们最近的博客文章中所述:
http://backstage.soundcloud.com/2012/06/building-the-next-soundcloud/
相关摘录:
为了解决这个问题,我们使用了一个我们称为实例存储的构造。此存储是一个对象,每次调用模型的构造函数时都会隐式访问和修改它。当第一次构建模型时,它会将自己注入到 store 中,使用它的 id 作为唯一键。如果使用相同的 id 调用相同的模型构造函数,则返回原始实例。
var s1 = new Sound({id: 123}),
s2 = new Sound({id: 123});
s1 === s2; // true, these are the exact same object.
这是因为 Javascript 的一个鲜为人知的特性。如果构造函数返回一个对象,那么这就是分配的值。因此,如果我们返回对先前创建的实例的引用,我们将获得所需的行为。在幕后,构造函数基本上是这样做的:
var store = {};
function Sound(attributes) {
var id = attributes.id;
// check if this model has already been created
if (store[id]) {
// if yes, return that
return store[id];
}
// otherwise, store this instance
store[id] = this;
}
我通过重写 Backbone.Model 类来创建我自己的构造函数来实现我的版本。
var MyModel = Backbone.Model.extend({
constructor: function (attributes, options) {
var id = attributes ? attributes.id : undefined;
if (this.store[id]) {
return this.store[id];
}
Backbone.Model.prototype.constructor.apply(this, arguments);
if (id) {
this.store[id] = this;
}
}
});
var MyOtherModel = MyModel.extend({
store: {},
//other model stuff
});
这工作得很好,但一定发生了一些变化,现在它停止工作了,我不确定为什么。新创建的实例毫无问题地存储在存储对象中 - 每个扩展 MyModel 类的类都有自己的空存储,以避免具有相同 id 的不同类型的实例发生冲突。当使用现有 id 调用构造函数时,也可以毫无问题地检索正确的实例,但是当它们从构造函数返回时,返回值将被忽略。我对规范的理解是,构造函数可以返回一个对象——但不能返回一个原始对象——并且当使用 new 运算符调用构造函数时,返回的对象将被分配到赋值语句的左侧。这不会发生,即使构造函数返回一个对象,
一些调试信息。不确定这些信息会有多大帮助。这是第一次实例化对象的 MyModel 构造函数中的“this”。
child
_callbacks: Object
_escapedAttributes: Object
_previousAttributes: Object
_setting: false
attributes: Object
id: "4fd6140032a6e522f10009ac"
manufacturer_id: "4f4135ae32a6e52a53000001"
name: "Tide"
uniqueName: "tide"
__proto__: Object
cid: "c50"
collection: child
id: "4fd6140032a6e522f10009ac"
__proto__: ctor
constructor: function (){ parent.apply(this, arguments); }
defaults: Object
store: Object
url: function () {
urlRoot: function () {
__proto__: ctor
当它是从实例存储返回的对象时,这是 MyModel 构造函数中的“this”:
child
_callbacks: Object
_escapedAttributes: Object
_previousAttributes: Object
_setting: false
attributes: Object
_validate: function (attrs, options) {
bind: function (events, callback, context) {
change: function (options) {
changedAttributes: function (diff) {
clear: function (options) {
clone: function () {
constructor: function (){ parent.apply(this, arguments); }
defaults: Object
destroy: function (options) {
escape: function (attr) {
fetch: function (options) {
get: function (attr) {
has: function (attr) {
hasChanged: function (attr) {
idAttribute: "id"
initialize: function (){}
isNew: function () {
isValid: function () {
manufacturer_id: 0
name: ""
off: function (events, callback, context) {
on: function (events, callback, context) {
parse: function (resp, xhr) {
previous: function (attr) {
previousAttributes: function () {
save: function (key, value, options) {
set: function (key, value, options) {
store: Object
toJSON: function () {
trigger: function (events) {
unbind: function (events, callback, context) {
unset: function (attr, options) {
url: function () {
urlRoot: function () {
__proto__: Object
cid: "c141"
__proto__: ctor
constructor: function (){ parent.apply(this, arguments); }
defaults: Object
store: Object
url: function () {
urlRoot: function () {
__proto__: ctor
我注意到的是,第二个中的属性对象包含其中包含的主干对象的所有方法,它们不应该是。它也没有id,我也不知道为什么。希望这能提供一些见解。谢谢。