Or, a quick lesson in how NOT to code in JS
My attempt at a JS object:
var InvoiceLine = function(number, quantity, description, line_price) {
this.number = number || lineCount;
this.quantity = parseFloat(quantity) || 1;
this.description = description || '';
this.line_price = parseFloat(line_price) || 0;
this.amount = this.quantity * this.line_price;
this.getAmount = function() { return this.quantity * this.line_price; }
};
line = new InvoiceLine();
line.line_price = formatMoney(line.line_price);
line.amount = formatMoney(line.amount);
class InvoiceLine extends Base
constructor: (number, description, quantity, linePrice, currency, invoice) ->
// ...
getAmount: ->
@_quantity * @_linePrice
setInvoice: (invoice) ->
@_invoice = invoice
@_number = invoice.lines.length + 1
var InvoiceLine,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { /* ... */ };
InvoiceLine = (function(_super) {
__extends(InvoiceLine, _super);
function InvoiceLine(number, description, quantity, linePrice, currency, invoice) {
this.accessor('number', 'description', 'quantity', 'linePrice', 'invoice');
this.readable('amount', 'currency');
this._invoice = invoice != null ? invoice : null;
this._quantity = quantity != null ? quantity : 1;
// ...
}
InvoiceLine.prototype.getAmount = function() { return this._quantity * this._linePrice; };
InvoiceLine.prototype.setInvoice = function(invoice) { this._invoice = invoice; return this._number = invoice.lines.length + 1; };
// Gruntfile.js
coffee: {
compile: {
options: {
join: true, bare: true
},
files: {
'src/invoice.js': 'src/*.coffee'
}
}
},
If you dip your toe, you might as well swim
grunt.loadNpmTasks('grunt-contrib-coffee');
grunt.loadNpmTasks('grunt-coffeelint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-clean');
// Default task(s).
grunt.registerTask('debug', ['coffeelint', 'coffee', 'concat', 'jasmine']);
grunt.registerTask('default', ['coffeelint', 'coffee', 'uglify']);
grunt.registerTask('test', ['default', 'jasmine']);
grunt.registerTask('build', ['test', 'compress']);
Debugging in the browser is difficult
Caching of the function
__hasProp = {}.hasOwnProperty;
__extends = function(child, parent) {
// Copy all the class-level methods and properties from the parent to the child
for (var key in parent) {
if (__hasProp.call(parent, key))
child[key] = parent[key];
}
// Set up the prototype link from the child to the parent
function ctor() {
this.constructor = child;
}
// and ensure that the instanceof operator works as expected
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
Caching of the function
__slice = [].slice;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
__indexOf = [].indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (i in this && this[i] === item)
return i;
}
return -1;
};
[].indexOf only supported in IE >= 9