Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does CoffeeScript wrap class definitions in a closure?

In CoffeeScript, this:

class Foo
  method: (x) ->
    x+1

Compiles to:

// Generated By CoffeeScript
Foo = (function() {
  function Foo() {}
  Foo.prototype.method = function(x) {
    return x+1;
  }
  return Foo;
})()

Which seems a bit excessive. The following should be functionally identical:

// Generated by Dave
function Foo() {}
Foo.prototype.method = function(x) {
    return x+1;
}

What is the motivation for the extra "closure" wrapper?

This is not merely an idle question of styling; it has implication to overall code size.

The Coffee version minifies into 84 bytes:

Foo=function(){function e(){}return e.prototype.method=function(e){return e+1},e}();

My version minifies into only 61 bytes:

function Foo(){}Foo.prototype.method=function(e){return e+1};

23 bytes is silly kinds of irrelevant, but in a project with many many classes, overhead begins to add up.

Ok, I wrote an answer below refuting the byte size theory ... for any reasonable class, the Coffee method is going to be smaller.

There's probably other reasons too. Help me think of them.

like image 751
Dave Dopson Avatar asked Aug 18 '12 01:08

Dave Dopson


People also ask

Should you use CoffeeScript?

CoffeeScript is something that makes even good JavaScript code better. CoffeeScript compiled code can do everything that natively written JavaScript code can, only the code produced by using CoffeeScript is way shorter, and much easier to read.

What is a .coffee File?

JavaScript file written in CoffeeScript, a programming language that compiles and transcompiles to JavaScript; saved in a text format and contains code that is similar to JavaScript, but modified to be more readable. CoffeeScript's aim is to enhance JavaScript's brevity and readability.


2 Answers

Another reason for wrapping the class definition with a closure is to give that code a new lexical scope for declaring variables and stuff that is only visible inside the class:

class AwesomeThing
  # You might have private "methods" here.
  doSomethingAwesome = (what) ->
    console.log "I'm doing #{what} like a pro!"
  # Or run any arbitrary code.
  for i in [1..10]
    @prototype["uselessMethod#{i}"] = -> 'nothing'

  beAwesome: ->
    doSomethingAwesome @uselessMethod5() # The 5'th useless method is the best.

In that code, the variables doSomethingAwesome and i are local to the class definition, thus making them "private" to outside users.

The CoffeeScript compiler could remove the extra wrapping if no local variables are needed IMO. But always wrapping the class definition is probably simpler from an implementation perspective :)

like image 118
epidemian Avatar answered Oct 02 '22 12:10

epidemian


I don't really know how CS works besides the fact that it just converts into JS, but the way I see it, the module pattern supports private members easily, which the prototype pattern doesn't (or would normally be hard to do). I believe that it's the main reason why module pattern is the pattern used.

like image 42
Joseph Avatar answered Oct 02 '22 12:10

Joseph