Share
Embed
How CoffeeScript deprecates Javascript
Stefano Verna
May 22, 2012
Transcript
68 slides
-
1995 Netscape wanted a lightweight interpreted language that would complement
Java by appealing to nonprofessional programmers, like Microsoft's Visual Basic. -
1995 JS had to “look like Java”, only less so.
It had to be Java’s dumb kid brother or boy- hostage sidekick. Plus, it had to be done in ten days. -
1995 Not a bad language, for a 10 days effort.
% Prototypal inheritance % First-class functions % First-class closures % Object and Array literals % Loose typing -
1995 Not a great language, neither. × Ugly, verbose syntax
× Dependency on globals × No block scopes × Equality coersion × A lot more -
1995 For 5 long years, it’s just news ticker and
countdown timers. 2000 -
1995 For 5 long years, it’s just news ticker and
countdown timers. 2000 -
var names = []; for (var i = 0, l
= people.length; i < l; i++) { var person = people[i]; var name = person.name.slice(0, 1).toUpperCase() + person.name.slice(1); names.push(name); } -
names = people.map do |person| person.name.capitalize end var names =
people.map( function (person) { return person.name.capitalize(); } ); -
var names = $.each(people, function(person) { return capitalize(person.name); } );
jQuery.noConflict() A broader audience, a safer approach A step backward in readability -
A desktop-like development experience There’s no HTML, CSS or JS
No direct interaction with the browser Java ObjC Python 2008 -
@implementation AppController : CPObject { } - (void)applicationDidFinishLaunching:(CPNotification)note { theWindow
= [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask]; contentView = [theWindow contentView]; var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; [label setStringValue:@"Hello World!"]; [label setFont:[CPFont boldSystemFontOfSize:24.0]]; [label sizeToFit]; [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin]; [label setFrameOrigin:CGRectMake(100,100)]; [contentView addSubview:label]; [theWindow orderFront:self]; } @end -
But I like the web! I just want the bad
parts fixed! ( -
2009 Underneath all those awkward braces and semicolons, JavaScript has
always had a gorgeous object model at its heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way. The golden rule of CoffeeScript is: "It's just JavaScript". CoffeeScript generates clean and readable JavaScript. -
(function() { /* your program here */ }).call(this); Private by
default (self-executing function) # Your program here -
function greet (name) { return "Hello " + name; }
Function syntax & automatic return greet = (name) -> "Hello " + name -
function greet (name) { return "Hello " + name; }
Function syntax & automatic return greet = (name) -> "Hello " + name Approved feature in ECMAScript.next http://goo.gl/JsXQ5 -
greet = (name) -> if name == "@tenderlove" "ZOMG! HI
" + name + "!!!" else "Hello " + name Everything is an expression var greet = function(name) { if (name === "@tenderlove") { return "ZOMG! HI " + name + "!!!"; } else { return "Hello " + name; } }; -
var names, person; names = (function() { var _i, _len,
_results; _results = []; for (_i = 0, _len = people.length; _i < _len; _i++) { person = people[_i]; _results.push(capitalize(person.name)); } return _results; })(); names = for person in people capitalize person.name Everything is an expression /2 -
"ZOMG! HI #{ name }!!!" Ruby-style string interpolation "ZOMG! HI
" + name + "!!!"; -
foo = false bar = "0" console.log foo == bar
# -> false console.log foo != bar # -> true Strict comparisons (no more equality coertion) var bar, foo; foo = false; bar = "0"; console.log(foo === bar); console.log(foo !== bar); -
foo = false bar = "0" console.log foo == bar
# -> false console.log foo != bar # -> true Strict comparisons (no more equality coertion) var bar, foo; foo = false; bar = "0"; console.log(foo === bar); console.log(foo !== bar); In JS, if you use == you’ll get the exactly opposite result! -
var changeNumbers, inner, outer; outer = 1; changeNumbers = function()
{ var inner; inner = -1; return outer = 10; }; inner = changeNumbers(); No more var (Ruby-like scoping) outer = 1 changeNumbers = -> inner = -1 outer = 10 inner = changeNumbers() -
var changeNumbers, inner, outer; outer = 1; changeNumbers = function()
{ var inner; inner = -1; return outer = 10; }; inner = changeNumbers(); No more var (Ruby-like scoping) outer = 1 changeNumbers = -> inner = -1 outer = 10 inner = changeNumbers() In JS, you omit “var” you’re leaking variables on the outer scope! -
var languageOfChoice = function(lang) { if (lang == null) {
lang = "Ruby"; } return "" + lang + " rocks!"; }; Parameter default values languageOfChoice = (lang = "Ruby") -> "#{ lang } rocks!" -
var languageOfChoice = function(lang) { if (lang == null) {
lang = "Ruby"; } return "" + lang + " rocks!"; }; Parameter default values languageOfChoice = (lang = "Ruby") -> "#{ lang } rocks!" Approved feature in ECMAScript.next http://goo.gl/JsXQ5 -
var __slice = [].slice; var languagesOfChoice = function() { var
best, others; best = arguments[0], others = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return "I love " + best + ", but I like also " + (others.join(", ")); }; Arguments splat languagesOfChoice = (best, others...) -> "I love #{ best }, but I like also #{ others.join(", ") }" -
var __slice = [].slice; var languagesOfChoice = function() { var
best, others; best = arguments[0], others = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return "I love " + best + ", but I like also " + (others.join(", ")); }; Arguments splat languagesOfChoice = (best, others...) -> "I love #{ best }, but I like also #{ others.join(", ") }" Approved feature in ECMAScript.next http://goo.gl/JsXQ5 -
console.log [ 1, 2, 3, ] console.log { foo: 1,
bar: 2, } JSLint validatable code (runs everywhere) console.log([1, 2, 3]); console.log({ foo: 1, bar: 2 }); -
console.log [ 1, 2, 3, ] console.log { foo: 1,
bar: 2, } JSLint validatable code (runs everywhere) console.log([1, 2, 3]); console.log({ foo: 1, bar: 2 }); IE would have thrown a compilation error on this one! -
return if elements.length == 0 launch() if ignition is on
volume = 10 if band isnt SpinalTap letTheWildRumpusBegin() unless answer is no if car.speed < limit then accelerate() winner = yes if pick in [47, 92, 13] Statement Modifiers & Operator aliases -
Multiline strings var mobyDick = "Call me Ishmael. Some years
ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..."; var html = "<strong>\n cup of coffeescript\n</strong>"; mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..." html = """ <strong> cup of coffeescript </strong> """ -
class Animal constructor: (@name) -> move: (meters) -> alert @name
+ " moved #{meters}m." dog = new Animal("Fido") var Animal = (function() { function Animal(name) { this.name = name; } Animal.prototype.move = function(meters) { return alert(this.name + (" moved " + meters + "m.")); }; return Animal; })(); Built-in classical OOP (the @ alias) -
var Animal, Snake, __hasProp = {}.hasOwnProperty, __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; }; Snake = (function(_super) { __extends(Snake, _super); function Snake() { return Snake.__super__.constructor.apply(this, arguments); } Snake.prototype.move = function() { alert("Slithering..."); return Snake.__super__.move.call(this, 5); }; return Snake; })(Animal); Inheritance class Snake extends Animal move: -> alert "Slithering..." super 5 -
Bound functions (fat arrow) class @View constructor: (@name) -> @el
= $("<div/>").appendTo("body") @attachEvents() attachEvents: -> @el.click -> alert "#{@name} view!" -
class @View constructor: (@name) -> @el = $("<div/>").appendTo("body") @attachEvents() attachEvents:
-> this.el.click( function() { alert(_this.name + " view"); } ); Bound functions (fat arrow) -
class @View constructor: (@name) -> @el = $("<div/>").appendTo("body") @attachEvents() attachEvents:
-> var _this = this; this.el.click( function() { alert(_this.name + " view"); } ); Bound functions (fat arrow) -
Bound functions (fat arrow) class @View constructor: (@name) -> @el
= $("<div/>").appendTo("body") @attachEvents() attachEvents: -> @el.click => alert "#{@name} view!" -
Bound functions (fat arrow) Approved feature in ECMAScript.next http://goo.gl/JsXQ5 class
@View constructor: (@name) -> @el = $("<div/>").appendTo("body") @attachEvents() attachEvents: -> @el.click => alert "#{@name} view!" -
Closure wrappers var number = 10; function check() { return
number; }; number = 20; check(); -
Closure wrappers var number = 10; function check() { return
number; }; number = 20; check(); // 20 -
Closure wrappers for (var i = 0; i < 5;
i++) { $("<div/>") .text(i) .appendTo("body") .click(function() { alert("Clicked " + i); }); } -
Closure wrappers for (var i=0; i<5; i++) { (function(i) {
$("<div/>") .text(i) .appendTo("body") .click(function() { alert("Clicked " + i); }); })(i); } -
Closure wrappers for i in [0...5] do (i) -> $("<div/>")
.appendTo("body") .text(i) .click -> alert("Clicked #{i}") -
Everything else you might miss from Ruby. • Array slicing
• Destructured assignments • Block regular expressions • Optional parenthesis • Existential operators