Я пытаюсь реализовать свою версию «Instance Store» в Backbone.js, как описано Soundcloud в их недавнем сообщении в блоге :
http://backstage.soundcloud.com/2012/06/building-the-next-soundcloud/
. Соответствующая выдержка:
Чтобы решить эту проблему, мы используем конструкцию, которую называем хранилищем экземпляров. Это хранилище является объектом, к которому неявно обращаются и изменяют каждый раз, когда вызывается конструктор для модели. Когда модель создается впервые, она внедряется в хранилище, используя свой идентификатор в качестве уникального ключа. Если тот же конструктор модели вызывается с тем же идентификатором, то возвращается исходный экземпляр.
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, имеет собственное пустое хранилище, чтобы избежать коллизий экземпляров другого типа с одним и тем же идентификатором. Правильный экземпляр также извлекается без проблем, когда конструктор вызывается с существующим идентификатором, однако, когда они возвращаются из конструктора, возвращаемое значение игнорируется. Насколько я понимаю из спецификации, конструкторы могут возвращать объект -, но не примитив -, и возвращаемый объект будет присваиваться левой части оператора присваивания, когда конструктор вызывается с оператором new.Этого не происходит, несмотря на то, что конструктор возвращает объект, используется пустой объект, созданный оператором new.
Немного отладочной информации. Не уверен, что эта информация будет полезна. Это «это» в конструкторе MyModel для объекта, который создается в первый раз.
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, когда это объект, возвращаемый из хранилища экземпляров:
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
Что я отмечаю, так это то, что объект атрибутов во втором имеет все методы магистрального объекта, включенные туда, чего не должно быть. У него также нет идентификатора, опять же, я не уверен, почему. Надеюсь, это дает некоторое представление. Спасибо.