I am programming with Backbone.js in CoffeeScript and have a problem with inheritance in relation with lodash and the merge function.
There is a superclass
class NavigationView extends Backbone.View
config:
test:
string: "Test"
and two classes derived from it
class SubView extends NavigationView
initialize: ->
# Setting the view's template property using the Underscore template method
_.merge @config, {
test:
string: "bla"
}
class IndexView extends NavigationView
...
If I change within SubView’s function initialize the config variable it is also changed in an instance of IndexView.
I instantiate my objects like so, within a BackBone.Router class:
index: () ->
# Instantiates a new view which will render the header text to the page
new IndexView()
sub: () ->
new SubView()
I created a fiddle to show it: http://jsfiddle.net/hijolan/9VeND/
Any ideas how to do that?
Best regards, hijolan
Your problem is that
_.mergemodifies its first argument in-place:Note that where the documentation says
destinationit really meansobject. The intent ofmergeis to be a deep version of_.extendand the Underscore docs are explicit about what happens:You’ll notice that lodash’s
extend(AKAassign) also gets the parameter names mixed up:Again they mean
objectwhen they saydestination.When you do this:
The
configends up attached to the prototype forNavigationViewand so the exact sameconfigobject will be seen byNavigationViewand its subclasses. That means that@configis the prototype’sconfigin yourinitialize:so
_.mergewill merge the new values right into the prototype’sconfigand that makes the change visible all the way up toNavigationViewand down into all of its subclasses. If you trace the inheritance back up, you’ll find that@configin that context is fromNavigationViewso your_.mergeis just a tricky and confusing way of writing:The root of the problem is that
_.extendand_.mergemodify their first argument. The way out of this trap is to supply a destination object that is safely writeable:Demo: http://jsfiddle.net/ambiguous/7j2FM/