arete
arete

Reputation: 1933

Is Backbone.*.extend setting the protoypal value for the defined class?

When using extend with collections and models are attributes that are not backbone methods set as the prototypal value of the defined "class"? Meaning that if those attributes are modified in one instance of the class they are changed for all instances of the class?

I'm running into a problem similar to that of the following.

For example :

var MyCollection = Backbone.Collection.extend({
options:
{
   someAttribute: null,
   anotherAttribute : null
},

url : function() 
{ 
    return this.options.someAttribute + "/" + this.options.anotherAttribute
});

var myCollectionInstance1 = new MyCollection();

_.extend(myCollectionInstance1.options,{
   someAttribute: "page1",
   anotherAttribute : "location1"});

var myCollectionInstance2 = new MyCollection();

_.extend(myCollectionInstance2.options,{
   someAttribute: "page1",
   anotherAttribute : "location2"});

// I call fetch here which will eventually run into my redefined url
// and now my url for this function is going to be 
// "page1/location2" instead of what I expect "page1/location1"
// I assume this is because the protoype is being changed in the above 
// of myCollectionInstance2.options
myCollectionInstance1.fetch();

If this is the case then what is the best way to attach instance variables to collections?

Upvotes: 1

Views: 40

Answers (2)

mu is too short
mu is too short

Reputation: 434785

Yes, everything in the first argument to extend ends up in the prototype and is thus shared by the instances. A common solution for mutable properties (such as objects and arrays) is to assign them inside initialize:

var MyCollection = Backbone.Collection.extend({
    initialize: function(options) {
        this.options = {
            someAttribute: null,
            anotherAttribute: null
        };
        // The rest of the initialization goes here...
    }
});

If you want to keep them where they are for documentation purposes, then you can _.clone in initialize:

var MyCollection = Backbone.Collection.extend({
    default_options: {
        someAttribute: null,
        anotherAttribute: null
    },
    initialize: function(options) {
        this.options = _(this.default_options).clone();
        // The rest of the initialization goes here...
    }
});

Note that _.clone only does a shallow copy so you can still end up with accidental sharing if this.options contains embedded arrays or objects.

Upvotes: 4

Rida BENHAMMANE
Rida BENHAMMANE

Reputation: 4129

Your problem is when you do this:

var MyCollection = Backbone.Collection.extend({
options:
{
   someAttribute: null,
   anotherAttribute : null
}

you are creating an object { someAttribute: null, anotherAttribute : null } that's shared with all the instances, and when you do this:

_.extend(myCollectionInstance1.options,{ ...

you are updating this shared object.

The solution to your problem is when you want to set the collection.options create new objects:

myCollectionInstance1.options = {
   someAttribute: "page1",
   anotherAttribute : "location1"
};

...

myCollectionInstance2.options = {
   someAttribute: "page1",
   anotherAttribute : "location2"
};

this way each collection will hold its own object.

Upvotes: 1

Related Questions