Following on from this question, I'm trying to augment Backbone.Collection with some custom methods. However, I'm getting some inconsistent behaviour between the console and the source.
Here's how the test looks
HTML
... <script type="text/javascript" src="./libs/underscore.js"></script> <script type="text/javascript" src="./libs/backbone.js"></script> <script type="text/javascript" src="./libs/backbone-extend.js"></script> <script type="text/javascript" src="./qunit/qunit.js"></script> <script type="text/javascript" src="./backbone-extend-tests.js"></script> </body></html>
backbone-extend.js
Backbone.Collection.prototype.extract = function() { // placeholder to test binding return 'foo'; };
backbone-extend-tests.js
test('extending backbone', function () { ok(typeof Backbone.Collection.extract == 'function'); console.log(Backbone.Collection.extract); // undefined });
Is there something I'm missing? I've checked that all the source is loading
JFTR - this...
_.extend(Backbone.Collection, {extract:function(){return'foo';});
...works, just not using the prototype augmenting method. I'm just unsure why one method works and the other doesn't, given that the docs for Backbone recommend prototype augmentation (although it specifically mentions Models). Guess I need to take a more detailed look under the bonnet...
UPDATE: for posterity, placing this in the backbone-extend.js file...
_.extend(Backbone.Collection.prototype, { extract : function (model) { var _model = model; this.remove(model); return _model; } });
... works
You are mixing up a few key concepts which is why you aren't seeing the behavior that you expect, which is more a fundamental javascript question and not entirely related to backbone.
Consider the following constructor:
var Klass = function() {};
You can invoke that constuctor using the new
keyword to get an instance from that constructor.
var klassInstance = new Klass();
Now, lets say I wanted to add a method that was available to all of the instances that are derivied from that constructor. For that I can use the prototype
object.
Klass.prototype.instanceMethod = function() { alert('hi'); };
Then I should be able to invoke that method using the following:
klassInstance.instanceMethod();
However, I can also add a static
Klass.staticMethod = function() { alert('yo!'); };
This method will be available directly off the constructor, but will not
For example:
klassInstance.staticMethod == undefined
So what's really wrong with your test is that you are adding a method to the prototype
An aside, though relevant, Backbone.js provides a built in mechanic to create "sub-classes" of thier built in types. This is the static .extend()
method. This provides you a simple way to add your own functionality to the base Backbone classes.
In your case you would want to do something like:
var MyCollection = Backbone.Collection.extend({ extract: function() { // do whatever } })
Then, you can create instances of your new classes, which will have an .extract()
method on them by saying:
var coll = new MyCollection(); coll.extract();
TL;DR;
test is incorrect. You either need to new up an instance to test against:
test('extending backbone', function () { var col = new Backbone.Collection(); ok(typeof col.extract == 'function'); });
Or check the prototype
prototype
object is not the only for an object to get a method.
test('extending backbone', function () { ok(typeof Backbone.Collection.prototype.extract == 'function'); });
make sure backbone.js
and underscore.js
is fully loaded before doing the tests.