I am just beginning to learn Coffeescript and cannot find a definite answer to why I should use
class Model extends Backbone.Model
urlRoot: '//some/url'
compiles to
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);
as opposed to
Model = Backbone.Model.extend
urlRoot: '//some/url'
compiles to
var Model = Backbone.Model.extend({
urlRoot: '//some/url'
});
The main reason I am asking is because the former is used in nearly all examples I have looked at. However, it creates 'much' more bloat when compiled as opposed to the latter. I did read this question, but the answers seem to differ.
I am just beginning to learn Coffeescript and cannot find a definite answer to why I should use
class Model extends Backbone.Model
urlRoot: '//some/url'
compiles to
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);
as opposed to
Model = Backbone.Model.extend
urlRoot: '//some/url'
compiles to
var Model = Backbone.Model.extend({
urlRoot: '//some/url'
});
The main reason I am asking is because the former is used in nearly all examples I have looked at. However, it creates 'much' more bloat when compiled as opposed to the latter. I did read this question, but the answers seem to differ.
Share Improve this question edited May 23, 2017 at 12:07 CommunityBot 11 silver badge asked Aug 13, 2013 at 6:36 TYRONEMICHAELTYRONEMICHAEL 4,2444 gold badges31 silver badges48 bronze badges 4- What exactly do you think "bloat" is? Why do you think it's bad? If you're talking about verbosity of code then... Why? It's generated code, it doesn't matter. – user229044 ♦ Commented Aug 13, 2013 at 12:53
- 1 @meagar, well if you writing a large scale app with many models, collections and views, the generated code definitely needs to matter. Also I would like the generated code to be easily read by those who have not yet learnt Coffeescript. – TYRONEMICHAEL Commented Aug 13, 2013 at 18:03
- 2 @TyroneMichael No, it really doesn't, any more than the generated binary matters in a modern desktop application. – user229044 ♦ Commented Aug 13, 2013 at 19:09
- 1 Looking at the results of these, the difference is about 17 bytes per class once run through a minifier. In a (fairly large) app I have about 45 classes, which equates to 765 bytes. Compare this to the total of 140,000 bytes it currently is. Worrying about this is a micro-optimization at best. – James Kyle Commented Jun 9, 2014 at 2:15
1 Answer
Reset to default 26 +300Since you're asking just about the bloat, let's have a look at some code.
JavaScript with Backbone.Model.extend
If you open up the Backbone source code, you'll see the extend
function is the following:
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;
};
What actually happens here:
When we call
var Model = Backbone.Model.extend({urlRoot: '//some/url' });
we get something like:
// 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;
CoffeeScript with extends
Compare that with the CoffeeScript code. You will see that when you use extends
a magical function called __extends
gets added to the start of your file, which (when formatted) looks like:
__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;
};
which is combined with the generated 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);
What actually happens here:
When we call
Model extends Backbone.Model
urlRoot: '//some/url'
we get something like:
// 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;
What do we see?
They look pretty similar don't they?
CoffeeScript is just JavaScript. If you are already using Backbone and want to avoid adding in the __extends
function in your generated source, then use Backbone.Model.extend
. If you want to avoid adding in Backbone all together then extends
does practically the same thing. The reason that so many examples don't use the latter is that Backbone is not required to use CoffeeScript - it just wouldn't make sense to have an example which relies on an external library.