最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - extending Backbone.Collection prototype - Stack Overflow

programmeradmin0浏览0评论

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 remend 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

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 remend 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

Share Improve this question edited May 23, 2017 at 12:07 CommunityBot 11 silver badge asked Oct 15, 2012 at 11:57 sunwukungsunwukung 2,8154 gold badges41 silver badges56 bronze badges 3
  • 2 Wait are you trying to add a method to the class or to an instance of the class. Those aren't the same thing. And why aren't you using backbones build in extend if you are doing the latter? – J. Holmes Commented Oct 15, 2012 at 12:01
  • I'm trying to add a method to the class, so that all collections have an "extract" method. If you take at my original question, I wanted a method that would give me back the item when calling Backbone.Collection.remove() – sunwukung Commented Oct 15, 2012 at 12:08
  • i'm not entirely sure you see what i mean – J. Holmes Commented Oct 15, 2012 at 14:32
Add a ment  | 

2 Answers 2

Reset to default 10

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 function – and I use the term loosely in this context – to the constructor itself, which can be invoked without having an instance.

Klass.staticMethod = function() { alert('yo!'); };

This method will be available directly off the constructor, but will not be available – directly – off of instances.

For example:

klassInstance.staticMethod == undefined

So what's really wrong with your test is that you are adding a method to the prototype – a method that will be available to all instances of that "class" – but in your test you are testing for a method directly on the "class" itself. Which is not the same thing.


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;

Ultimately – back to your original question – if you want a method that will be available on all instances of a particular class, then your 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 directly for a method – this is subtlely different in the fact that the 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.

发布评论

评论列表(0)

  1. 暂无评论