为什么CoffeeScript在闭包中包装类定义?

时间:2012-08-18 01:34:19

标签: javascript coffeescript minify

在CoffeeScript中,this

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

编译为:

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

这似乎有点过分。以下内容应功能相同

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

额外的“封闭”包装器的动机是什么?

这不仅仅是造型的空闲问题;它对整体代码大小有影响。

Coffee版本缩小为84个字节:

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

我的版本只缩小为61个字节:

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

23个字节是愚蠢的无关紧要,但在一个有很多类的项目中,开销开始累计。

好的,我在下面写了一个驳回字节大小理论的答案......对于任何合理的类,咖啡方法都会变小。

也可能还有其他原因。帮我想一想。

4 个答案:

答案 0 :(得分:8)

使用闭包包装类定义的另一个原因是为该代码提供一个新的词法范围,用于声明仅在类中可见的变量和内容:

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.

在该代码中,变量doSomethingAwesomei是类定义的本地变量,从而使它们对外部用户“私有”。

如果不需要局部变量,CoffeeScript编译器可以删除额外的包装IMO。但是从实现的角度来看,总是包装类定义可能更简单:)

答案 1 :(得分:3)

我真的不知道CS是如何工作的,除了它只是转换成JS,但我看到的方式,module pattern supports private members easily,原型模式没有(或通常很难做)。我认为这是模块模式使用模式的主要原因。

答案 2 :(得分:2)

好的,我想我刚回答了自己的问题。

对于大多数合理的类,CoffeeScript生成的闭包会产生较小的缩小输出。

封闭包装器是25字节的缩小开销,但 可以避免重复类名 ,从而节省k * N个字节(k = letters-in- name,N = num-of-refs)。 例如,如果像BoilerPlateThingyFactory这样的类有2个以上的方法,则闭包装器生成较小的缩小代码。



更详细......

使用闭包的Coffee生成的代码缩小为:

// 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;
}();

替代实现缩小了:

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

注意名称“Animal”名称在Coffee表单中只存在一次,在替代实现中N = 2次。现在“动物”只有6个字母,而且只有1个方法,所以这里的咖啡应该输掉25-6 = 19个字节。咨询我的缩小代码,它是138字节到119字节,对于19字节的增量。再添加4种方法,优势将转向咖啡。而且这不仅仅是方法;类常量和其他引用类型也算数。

答案 3 :(得分:2)

Jeremy answers this over in a related question - 看起来主要意图是避免触发IE错误。