【问题标题】:Coffeescript class extend more bloat than Backbone extendCoffeescript 类比 Backbone 扩展更多膨胀
【发布时间】:2013-08-14 15:55:15
【问题描述】:

我刚开始学习 Coffeescript,找不到明确的答案来解释为什么我应该使用

class Model extends Backbone.Model
    urlRoot: '//some/url'

编译成

Model = (function(_super) {
    __extends(Model, _super);

    function Model() {
        _ref = Model.__super__.constructor.apply(this, arguments);
        return _ref;
    }

    Model.prototype.urlRoot = '//some/url';

    return Model;

})(Backbone.Model);

相对

Model = Backbone.Model.extend
    urlRoot: '//some/url'

编译成

var Model = Backbone.Model.extend({
    urlRoot: '//some/url'
});

我问的主要原因是因为前者几乎在我看过的所有示例中都使用过。但是,与后者相比,它在编译时会产生“更多”的膨胀。我确实读过这个question,但答案似乎不同。

【问题讨论】:

  • 你认为“膨胀”到底是什么?为什么你认为它很糟糕?如果您在谈论代码的冗长性,那么...为什么?是生成的代码,没关系。
  • @meagar,如果你编写一个包含许多模型、集合和视图的大型应用程序,那么生成的代码肯定很重要。我还希望那些还没有学习过 Coffeescript 的人可以轻松阅读生成的代码。
  • @TyroneMichael 不,它真的没有,就像现代桌面应用程序中生成的二进制文件一样重要。
  • 查看这些结果,每次运行一次压缩器后,每个类的差异约为 17 个字节。在一个(相当大的)应用程序中,我有大约 45 个类,相当于 765 个字节。将此与当前的 140,000 字节总数进行比较。对此的担忧充其量只是一种微优化。

标签: javascript backbone.js coffeescript


【解决方案1】:

既然你只是问膨胀,让我们看看一些代码。

JavaScript 与 Backbone.Model.extend

如果你打开 Backbone 源代码,你会看到 extend 函数如下:

var extend = function(protoProps, staticProps) {
    var parent = this;
    var child;

    if (protoProps && _.has(protoProps, 'constructor')) { // _.has comes from
      child = protoProps.constructor;                     // underscore, even 
    } else {                                              // more 'bloat'
      child = function(){ return parent.apply(this, arguments); };
    }

    _.extend(child, parent, staticProps);                // more underscore

    var Surrogate = function(){ this.constructor = child; };
    Surrogate.prototype = parent.prototype;
    child.prototype = new Surrogate;

    if (protoProps) _.extend(child.prototype, protoProps);

    child.__super__ = parent.prototype;

    return child;
  };

这里实际发生了什么:

当我们打电话时

var Model = Backbone.Model.extend({urlRoot: '//some/url' });

我们得到类似的东西:

  // Create new constructor which calls the parent constructor
  var Model;
  if (({}).hasOwnProperty.call({urlRoot: '//some/url' }, 'constructor') {
      // this is false so...                    
  } else {
      Model = function(){ return Backbone.Model.apply(this, arguments); };
  }

  // Set up prototype chain
  var Surrogate = function(){ this.constructor = model; };
  Surrogate.prototype = Backbone.Model.prototype;
  Model.prototype = new Surrogate;

  // Add properties to the child prototype
  // Same as:
  // Model.prototype.urlRoot = '//some/url';
  _.extend(Model.prototype, { urlRoot: '//some/url' });

  // Set the magical __super__ property
  Model.__super__ = Backbone.Model.prototype;

带有extends的CoffeeScript

将其与 CoffeeScript 代码进行比较。您会看到,当您使用 extends 时,一个名为 __extends 的神奇函数会添加到文件的开头,它(格式化后)如下所示:

__extends = function(child, parent) { 
    for (var key in parent) { 
        if (__hasProp.call(parent, key)) 
            child[key] = parent[key]; 
    }

    function ctor() { this.constructor = child; } 
    ctor.prototype = parent.prototype; 
    child.prototype = new ctor(); 

    child.__super__ = parent.prototype; 

    return child; 
};

结合生成的JS:

var Model = (function(_super) {
    __extends(Model, _super);

    function Model() {
        _ref = Model.__super__.constructor.apply(this, arguments);
        return _ref;
    }

    Model.prototype.urlRoot = '//some/url';

    return Model;

})(Backbone.Model);

这里实际发生了什么:

当我们打电话时

Model extends Backbone.Model
    urlRoot: '//some/url'

我们得到类似的东西:

// Create new constructor which calls the parent constructor
var Model = function () {
    return Model.__super__.constructor.apply(this, arguments);
}

// Copy static properties from Backbone.Model to Model
for (var key in Backbone.Model) {
    if (__hasProp.call(Backbone.Model, key)) 
        Model[key] = Backbone.Model[key]; 
}

// Set up prototype chain
function ctor() { this.constructor = Model; } 
ctor.prototype = Backbone.Model.prototype; 
Model.prototype = new ctor(); 

// Add properties to the child prototype
Model.prototype.urlRoot = '//some/url';

// Set the magical __super__ property
Model.__super__ = Backbone.Model.prototype; 

我们看到了什么?

它们看起来很相似不是吗?

CoffeeScript 只是 JavaScript。如果您已经在使用 Backbone 并且希望避免在生成的源代码中添加 __extends 函数,请使用 Backbone.Model.extend。如果您想避免一起添加 Backbone,那么 extends 几乎可以做同样的事情。这么多示例不使用后者的原因是 Backbone 不需要使用 CoffeeScript - 拥有一个依赖于外部库的示例是没有意义的。

【讨论】:

  • 哇,感谢您提供的信息丰富的答案。自从 Backbone 早期发布以来,我一直在开发它。我只是看了一些结合使用 Backbone 和 Coffeescript 的示例,并且大多数使用类示例。如果您有很多模型、集合和视图,文件大小会很快增加。
  • jsperf.com/backbone-extend-vs-coffeescript-class-extends 比较两个扩展的运行时间——它们是相似的。
  • 这里的关键区别在于 Backbone 扩展是一个方法调用,而 Coffeescript 扩展发出代码。这对代码大小有非常不同的影响。您需要清楚自己在优化什么。
  • 我不确定这是否会增加答案的价值,但是 Backbone 和 CoffeeScript 的作者是同一个最伟大的 Jeremy Ashkenas github.com/jashkenas ,所以我怀疑会有很大的(如果有的话) ) 两者扩展工作方式的差异。
猜你喜欢
  • 1970-01-01
  • 2011-04-13
  • 1970-01-01
  • 2015-09-18
  • 1970-01-01
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
相关资源
最近更新 更多