Как лучше понять Coffeescript/JavaScript mixins?

Я читал на Mixins, используя Coffeescript или просто Javascript из следующих источников:

http://arcturo.github.com/library/coffeescript/03_classes.html (внизу)

и

http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/

И хотя я могу скомпилировать различные примеры, у меня есть главный вопрос, который, кажется, мешает мне добиться прогресса в их понимании.

Я понятия не имею, что происходит в мире. Чтобы начать, я объясню, что Коффисскрипт меня смущает.

moduleKeywords = ['extended', 'included']

    class Module
      @extend: (obj) ->
        for key, value of obj when key not in moduleKeywords
          @[key] = value

        obj.extended?.apply(@)
        this

      @include: (obj) ->
        for key, value of obj when key not in moduleKeywords
          # Assign properties to the prototype
          @::[key] = value

        obj.included?.apply(@)
        this

Здесь возникает ряд вопросов.

  • Прежде всего, что мы делаем с переменной moduleKeywords? Я не понимаю, что это делает.

  • Во-вторых, как работает extended?.apply(@)? Что здесь происходит? Я могу посмотреть компиляцию JavaScript и посмотреть следующий код.

Module.extend = function(obj) {
      var key, value, _ref;
      for (key in obj) {
        value = obj[key];
        if (__indexOf.call(moduleKeywords, key) < 0) {
          this[key] = value;
        }
      }
      if ((_ref = obj.extended) != null) {
        _ref.apply(this);
      }
      return this;
    };

Может ли кто-нибудь пролить некоторый общий свет на это?

С более глубоким нажатием The Little Book on Coffeescript я вижу реализацию.

ORM = 
  find: (id) ->
  create: (attrs) ->
  extended: ->
    @include
      save: -> 

class User extends Module
  @extend ORM

Вот как я это прочитал:

  • создать литерал ORM.
  • Объявить метод find принятия параметра.
  • Объявить метод "create", принимающий параметр.
  • Объявить метод 'extended', с под-методом 'include', с под-методом 'save'.

Здесь я получаю самую большую потерю.

Литеральный ORM имеет метод extended, а затем Module реализуется/расширяется классом User. Поэтому я считаю, что User имеет ту же форму, что и Module. Эта часть имеет смысл до сих пор, упрощенное наследование. Но потом я теряюсь на @extend ORM.

@extend - это метод на Module, но что делает метод extended? Когда это называется? Как это реализовано?

Ответы

Ответ 1

  • extend копирует методы из объекта "module" на расширяемый объект
  • include копирует методы из объекта "module" на прототип расширяемого объекта

1 moduleKeywords используется для защиты некоторых методов модуля, поэтому они не копируются в объект, потому что они имеют особое значение

2 extended?.apply(@) говорит, что , если модуль имеет свойство с именем extended, чем предполагать его функцией, а затем вызывает эту функцию с "this" в функции, равной @, @, являющейся расширенным объектом, вы можете думать об этом как о чем-то вроде (хотя и не совсем, но это просто интуиция) @.extended() (@== this in coffeescript)

"применить" функцию в JS
экзистенциальный оператор в CS

Ответ 2

Вы путаетесь по смыслу и используете расширенные и включенные ключевые слова модуля. Но в книге объясняется, что они используются как обратные вызовы после расширения и включения.

Итак, в последнем примере ORM имеет "расширенный" обратный вызов. Функция "продлить" будет в конце вызова "расширена" и передать ее @(или это или в нашем примере User), так что включение @(this.) Также будет выполняться на пользователе, и оно будет включать функцию "сохранить".

Вы также можете сделать обратное:

ORM = 
  save ->
  included: ->
    @extend
      find: (id) ->
      create: (attrs) ->

class User extends Module
  @include ORM