8

在 CoffeeScript 中,这个

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 字节是愚蠢的无关紧要,但在一个有许多类的项目中,开销开始增加。

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

应该还有其他原因。帮我想想他们。

4

4 回答 4

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是类定义的本地变量,因此使它们对外部用户“私有”。

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

于 2012-08-18T02:15:46.173 回答
3

我真的不知道 CS 是如何工作的,除了它只是转换成 JS,但在我看来,模块模式很容易支持私有成员,而原型模式没有(或者通常很难做到) . 我相信这是使用模块模式的主要原因。

于 2012-08-18T01:48:18.763 回答
2

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

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

闭包包装器减少了 25 个字节的开销,但它使您免于重复 classname,节省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 次。现在“Animal”只有 6 个字母,而且只有 1 个方法,所以这里的 Coffee 应该会丢失 25-6 = 19 个字节。咨询我的缩小代码,它是 138 字节到 119 字节,增量为 ... 19 字节。再增加4个方法,优势会切换到Coffee。这不仅仅是方法;类常量和其他 ref 类型也很重要。

于 2012-08-18T01:34:18.523 回答
2

Jeremy 在一个相关问题中回答了这个问题——看起来主要目的是避免触发 IE 错误。

于 2012-08-18T18:20:25.733 回答