Do not initialise your subclass properties in backbone’s extend!

You definitely don’t want to do this, no no no!

It’s one of those time when you’re looking at the console log going “what the'”..

Then you realise your mistake and see how obvious it is.. duh!

Background – PHP

I’m going start this javascript post with some php.. I think years of writing php code has influenced the mistake.

Here’s a typical class definition in PHP.

class Test {

    public $items = array();

    public function addItem($item)
    {
        $this->items[] = $item;
        return $this;
    }
}

And a simple use for it:

$test1 = new Test;
$test2 = new Test;

$test1->addItem("A string")->addItem("Another");

$test2->addItem("This is different");


var_dump($test1->items);
var_dump($test2->items);

Yes, I just wrote the best class ever. Quick, someone write a php framework around it!

Stupid Mistake – Javascript/Backbone

So at the moment I’m writing some Backbone code… A lot of it involves subclassing Backbone Views.

Here’s a straight forward equivalent of the above PHP class as a Backbone view subclass:

var TestView = Backbone.View.extend({

    items: [],

    addItem:function(item)
    {
        this.items.push(item);
        return this;
    }

});

var test1 = new TestView();
var test2 = new TestView();

test1.addItem("A string").addItem("Another");

test2.addItem("This is different");


console.log(test1.items);
console.log(test2.items);

Can you guess the output of the last two console.log statements?

Well the output is:

["A string", "Another", "This is different"]
["A string", "Another", "This is different"]

Now imagine that on a much bigger scale project with hundreds of lines of code.. what the!

So what’s going on here?

Excellent question.

Well, first thing, when the Backbone.View.extend({/*..*/}) statement is executed, it’s important to note that [] is evaluated at that time, so it’s physically instantiated here, once.

Then it kind of acts like a static variable.. if you console.log the variables test1 and test2, you’ll notice that items is a property of __proto__.

Chrome will only show the property inside proto but firefox will show it as both inside proto and as an instance variable.

Essentially, you have a shared reference to an instanced array (created when first calling []).

How do i fix it?

Well, instantiate variables in a constructor, duh…

constructor: function()
{
     Backbone.View.prototype.constructor.apply(this, arguments);
     this.items = [];
}

.. and save yourself 1h of wtf-debugging!

If anyone has more input on this instance variable thing, please comment..

One comment on “Do not initialise your subclass properties in backbone’s extend!

Leave a Reply

Your email address will not be published. Required fields are marked *