Reputation: 78
I believed I had a good background in backbone.js but I have a problem I don't understand.
Suppose we have these two views:
BaseView = Backbone.View.extend({
foo: {},
initialize: function(options) {
this.render();
},
render: function() {
// ...
}
});
PageView = BaseView.extend({
render: function() {
this.foo.bar = 23;
}
});
If we check the attribute 'foo' in both views, obviously, it will be an empty object:
> BaseView.prototype.foo
Object {}
> PageView.prototype.foo
Object {}
But if we create a PageView instance, the 'foo' attribute from BaseView will be changed. How is that possible?
> page = new PageView()
> page.foo
Object {foo: 23}
> BaseView.prototype.foo
Object {foo: 23}
[Edit]
Actually, it's a general OOP question. In python:
class A(object):
foo = {}
class B(A):
def __init__(self):
self.foo['bar'] = 23
>>> print A.foo
{}
>>> b = B()
>>> print A.foo
{'bar': 23}
Upvotes: 2
Views: 188
Reputation: 434615
When you do this:
BaseView = Backbone.View.extend({
foo: {},
//...
});
That foo: { }
gets attached to the BaseView
prototype. That means that that exact object is shared by all instances of BaseView
and by all instances of any BaseView
"subclasses". So given this:
var BaseView = Backbone.View.extend({
foo: {},
//...
});
var PageView = BaseView.extend({
//...
});
var bv = new BaseView;
var pv = new PageView;
the data really looks like this:
bv.foo -->--+-->-- BaseView.prototype.foo -->-- { }
|
pv.foo -->--/
so if you alter pv.foo
with something like pv.foo.x = y
, you're actually altering BaseView.prototype.foo
and that's the same object as bv.foo
; of course if you pv.foo = something_else
then you've changed the reference and bv.foo
and pv.foo
will no longer refer to the same underlying object. You have only one underlying object with multiple references to it.
There is no copying (neither shallow nor deep) when you instantiate or extend your BaseView
or PageView
, you're just sharing a single reference to the underlying object.
If you want your foo
to be instance-specific (as you almost always do), then set it up in your constructor:
var BaseView = Backbone.View.extend({
initialize: function() {
this.foo = { };
//...
},
//...
});
Of course, the initialize
methods don't chain by themselves so you'll have to do that yourself if your PageView
needs one:
var PageView = BaseView.extend({
initialize: function() {
BaseView.prototype.initialize.apply(this, arguments);
// Whatever else you need done...
},
//...
});
Demo: http://jsfiddle.net/ambiguous/4duQ5/
Also, you really should be saying var BaseView
rather than just BaseView
, no var
means that you're creating a global and you probably don't want to do that.
Upvotes: 2