Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pushing to properties in Backbone [duplicate]

I spent a lot of time trying to catch a bug in my app. Eventually I set apart this piece of code which behavior seems very strange to me.

var Model = Backbone.Model.extend({
    myProperty: []
});

var one = new Model();
var two = new Model();
one.myProperty.push(1);
console.log(two.myProperty); //1!!

What's the reason behind it? Why it acts so? How to avoid this type of bugs in code?

like image 472
alexb Avatar asked Dec 19 '14 13:12

alexb


2 Answers

Inheritance in JavaScript is prototypical - objects can refer directly to properties higher up in the prototype chain.

In your example, one and two both share a common prototype, and do not provide their own values for myProperty so they both refer directly to Model.protoype.myProperty.

You should create new myProperty array for each model you instantiate. Model.initialize is the idiomatic place for this kind of initialisation - overriding constructor is unnecessarily complex.

var Model = Backbone.Model.extend({
    initialize: function() {
      this.myProperty = [];
    }
});

Alternatively you could make myProperty as an attribute of the model:

var Model = Backbone.Model.extend({
    defaults: function() {
      return {
        myProperty: []
      }
    }
});

It is important to note that defaults is a function - if you were to use a simple object you would encounter the same shared reference issue.

like image 52
joews Avatar answered Oct 29 '22 17:10

joews


Actually its because myProperty is an array, and as you know arrays will be stored by reference. Just to test consider the following code:

var Model = Backbone.Model.extend({
 myProperty: [],
 messege: ''
});

var one = new Model();
var two = new Model();

one.messege = 'One!';
two.messege = 'Two!';

console.log(one.messege ); // 'One!'
console.log(two.messege ); // 'Two!'

An alternative around this could be:

var Model = Backbone.Model.extend({
  constructor: function() {
    this.myProperty = [];
    Backbone.Model.apply(this);
  }
});

var one = new Model();
one.myProperty.push(1);

var two = new Model();
console.log(two.myProperty); // []
like image 26
sadrzadehsina Avatar answered Oct 29 '22 16:10

sadrzadehsina