Backboneの拡張、extendEachで複数のオブジェクトをextendする

Backboneを使っていると、あるCollectionの機能を別のCollectionでも使いたかったり、共通化したかったりする場面があります。

そんなときは、以下のようにextendメソッドでsubclassを作ることが多いと思います。

 

var ParentCollection = Backbone.Collection.extend(properties);

var ChildCollection = ParentCollection.extend({
  ...
});

 

引き継ぎたいpropertiesが1つである場合には上のようにすれば問題ありません。

ParentCollectionは、Backbone.Collection.extendで作成されていて、extendメソッドが使えます。

さらに、ParentCollectionのextendメソッドを使って、ChildCollectionにプロパティを引き継ぐこともできます。

 

ただ、extendメソッドにpropertiesは一つしか渡せず、2つ目以降はインスタンスプロパティではなく、クラスプロパティになります。

なので、複数のpropertiesを渡せるようにしたいときは、以下のようにBackboneを拡張します。

 

function extendEach() {
  var child = this
    , args = Array.prototype.slice.call(arguments)
    , len = args.length;

  return _.reduce(args, function(child, o, i) {
    return (i >= len - 1) ? child.extend(o) : child.extend(o.prototype);
  }, child);
}

Backbone.Collection.extendEach = extendEach;

 

Underscore.jsのreduce使って、順番にextendを実行していくメソッドです。

上の例では、Backbone.Collectionしか拡張していませんが、もちろんModelやView、Routerにも代入してあげれば、extendと同じ要領でextendEachが使えるようになります。

 

var GrundChildCollection = Backbone.Collection.extendEach(ParentCollection, ChildCollection, {
  ...
});

 

Backboneを拡張せず、グローバルな関数として作成したいときは以下のようにしてもいいかもしれません。

 

function extendEach() {
  var args = Array.prototype.slice.call(arguments)
    , len = args.length;

  return _.reduce(args, function(child, o, i) {
    return (i >= len - 1) ? child.extend(o) : child.extend(o.prototype);
  });
}