Невозможно продлить backbone.events в coffeescript

Я получаю сообщение об ошибке:

Uncaught TypeError: Cannot read property 'constructor' of undefined 

При объявлении следующего класса:

 class ViewHelpers extends Backbone.Events

Я могу использовать один и тот же синтаксис для расширения Backbone.Router, Views, Model и т.д. Вот компилируемый javascript, который я написал в кратком журнале, чтобы убедиться, что Backbone.Events был там

__t('views').ViewHelpers = (function(_super) {

 #how i know it is definied here
 console.log(_super.trigger)

 __extends(ViewHelpers, _super);

 function ViewHelpers() {
   return ViewHelpers.__super__.constructor.apply(this, arguments);
 }

 return ViewHelpers;

})(Backbone.Events);

Таким образом, строка, вызывающая ошибку,

ViewHelpers.__super__.constructor.apply(this, arguments);

Чем отличается метод __extends(), который будет работать для Backbone.View, а не Backbone.Events?

Ответы

Ответ 1

Это потому, что Backbone.Events не является "классом", поэтому он не может быть расширен, это "модуль", который можно смешивать с другими объектами (см. docs здесь). В терминах JavaScript это означает, что это не Function, который может быть вызван как конструктор (т.е. new Backbone.Events выдаст ошибку), это просто простой объект JS, свойства (методы которого) могут быть назначены другим объектам, чтобы сделать их диспетчеров событий.

В CoffeeScript вы можете перемешать Backbone.Events в свои объекты при их создании:

class ViewHelpers
  constructor: ->
    _.extend @, Backbone.Events

Или вы можете просто расширить прототип класса и избежать использования этих методов в качестве (собственных) свойств всех экземпляров ViewHelpers:

class ViewHelpers
  _.extend @prototype, Backbone.Events

Эти два подхода должны работать и позволить вам создавать экземпляры и использовать ViewHelpers в качестве диспетчеров событий:

vh = new ViewHelpers
vh.on 'foo', -> alert 'bar'
vh.trigger 'foo'​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

Ответ 2

Там другой способ (из того, что ответил @epidemian), который не предполагает копирование Backbone.Events в новый объект для использования в качестве вашего прототипа - вместо этого используйте Object.create для создания нового объекта для использования в качестве своего прототипа, используя Backbone.Events в качестве своего прототипа.

class ViewHelpers
  @prototype = Object.create(Backbone.Events)

Теперь прототип ViewHelpers '- это новый пустой объект, прототипом которого является Backbone.Events. Вы можете определять методы на прототипе ViewHelpers ', не затрагивая Backbone.Events, но все методы Backbone.Events по-прежнему доступны для ViewHelpers, без необходимости копировать их в новый объект. Это не только экономит (минимальное количество) памяти, но если вы закончите добавление к Backbone.Events позже, все ViewHelpers увидят это изменение.

Для этого вам понадобится браузер с функцией ES5 Object.create или a Object.create polyfill.

Ответ 3

Чтобы опираться на отличный ответ от @epidemian, я бы добавил это, это немного взломал, но он позволяет вам писать свой класс с помощью оператора extends, как вы указали в вопросе (который позволяет вам называть super для всех методов Backbone.Events):

class Events
_.extend Events.prototype, Backbone.Events

class CustomEvents extends Events

    trigger: (event, etc...) ->
        # You can add overrides before
        super "custom:#{event}", etc...
        # or after the super class methods

Было бы здорово работать с вызовом _.extend в функции Events.constructor, но я не мог заставить его работать...