Why does CoffeeScript wrap class definitions in a closure?

别说谁变了你拦得住时间么 提交于 2020-01-11 08:20:22

问题


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.


回答1:


Jeremy answers this over in a related question - it looks like the primary intent is to avoid triggering an IE bug.




回答2:


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 :)




回答3:


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.




回答4:


OK, I think I just answered my own question.

For most reasonable classes, the closure generated by CoffeeScript generates smaller minified output.

The closure wrapper is 25 bytes of minified overhead, but it saves you from repeating the classname, saving k * N bytes (k=letters-in-name, N=num-of-refs). e.g., if a class like BoilerPlateThingyFactory has 2+ methods, the closure wrapper generates smaller minified code.



in more detail...

The Coffee generated code using a closure minifies to:

// Uglify '1.js' = 138 bytes (197 w/ whitespace):

var Animal=function(){function e(e){this.name=e}return e.prototype.speak=function(e){return"My name is "+this.name+" and I like "+e},e}();

// with whitespace ("uglifyjs -b"):

var Animal = function() {
    function e(e) {
        this.name = e;
    }
    return e.prototype.speak = function(e) {
        return "My name is " + this.name + " and I like " + e;
    }, e;
}();

The alternative implementation minifies to this:

// Uglify '2.js' = 119 bytes (150 w/ whitespace):

var Animal=function(t){this.name=t};Animal.prototype.speak=function(e){return"My name is "+this.name+" and I like "+e};

// with whitespace ("uglifyjs -b"):

var Animal = function(t) {
    this.name = t;
};

Animal.prototype.speak = function(e) {
    return "My name is " + this.name + " and I like " + e;
};

Notice how the name "Animal" name exists precisely once in the Coffee form, and N=2 times in the alternative implementation. Now "Animal" is only 6-letters, and there's only 1 method, so Coffee here should lose by 25-6 = 19 bytes. Consulting my minified code, it's 138 bytes to 119 bytes, for a delta of ... 19 bytes . Add 4 more methods, and the advantage will switch to Coffee. And it's not just methods; class constants and other ref types count too.



来源:https://stackoverflow.com/questions/12015102/why-does-coffeescript-wrap-class-definitions-in-a-closure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!