Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to better understand Coffeescript/JavaScript mixins?

I have been reading up on Mixins using Coffeescript or just plain Javascript from the following sources:

http://arcturo.github.com/library/coffeescript/03_classes.html (near the bottom)

and

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

And while I am able to compile the various examples, I have a major question that seems to be preventing me from making progress in comprehending them.

I have no idea what in the world is going on. To start, I will explain the Coffeescript that is confusing me.

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

A number of questions come up here.

  1. First of all, what are we accomplishing with the moduleKeywords variable? I'm not understanding what that is doing.

  2. Secondly, how does extended?.apply(@) work? What is really going on here? I can look at the JavaScript compilation and see the following code ..

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;
    };

Can anyone shed some general light on this?

From deeper down in The Little Book on Coffeescript, I see an implementation.

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

class User extends Module
  @extend ORM

Here is how I read this:

  • create literal ORM.
  • Declare method find accepting a parameter.
  • Declare method 'create' accepting a parameter.
  • Declare method 'extended', with sub-method 'include', with sub-method 'save'.

This is where I get the most lost.

The literal ORM has a method, extended, and then Module is implemented/extended by the 'class' User. So I take this to mean that User has the same shape as Module. That part makes sense so far, simplistic inheritance. But then I get lost on @extend ORM.

@extend is a method on Module, but what is the extended method doing? When is it called? How is it implemented?

like image 366
Ciel Avatar asked Jan 04 '12 13:01

Ciel


1 Answers

  • extend copies the methods from the "module" object onto the object being extended
  • include copies the methods from the "module" object onto the prototype of the object being extended

1 The moduleKeywords is used to protect some methods of the module, so the are not copied to object, because they have special meaning

2 The extended?.apply(@) says that if the module has a property named extended than assume it's a function and then call this function having the "this" in the function equal to @, @ being the extended object, you can think of it as saying something like (although not quite, but it's just an intuition) @.extended() (@ == this in coffeescript)

"apply" function in JS
the existential operator in CS

like image 123
clyfe Avatar answered Oct 05 '22 18:10

clyfe