S

CoffeeScript

No really, it’s just Javascript
Brian Mann
@be_mann
Atlanta, GA
What is CoffeeScript?

• Exposes the good parts
• Transpiles directly to JS
• Removes / Adds new syntax
• Enhances readability, and productivity
• Clearly expresses intents
Agenda

• An Emotional Assessment
• Dive Into Features
• Real World Experiences
• Challenges / Critiques
I am Biased.
CoffeeScript
is one of the most
BEAUTIFUL

/

UGLY

LOVED

/

HATED

EMBRACED

/

FEARED

LANGUAGES.

/

TOOLS.

/

SYNTAX.
Javascript
Landscape.
Golden Age
S

Golden Age

CoffeeScript
Why the hate?

• CoffeeScript looks different
• CoffeeScript acts different
FUD.
Fear. Uncertainty. Doubt.
Crutch.
Absolutely

NOT.
S
Nothing To Fear.
Its just Javascript.
Okay thx.
Code plz.
Before we begin

•
• No more commas
• Optional parenthesis
• Optional curly braces
• White space sensitive

No more semi-colons ;
,
()
{}
Vars.
var is, no, more;
Vars are long gone
var count, increment;

JAVASCRIPT

count = 0;
increment = function() {
var total;
count += 1;
return total = "The total is: " + count;
};

count = 0

COFFEESCRIPT

increment = ->
count += 1
total = "The total is: " + count
Rule:

/
100

99
Object Literals.
Objects Simplified
JAVASCRIPT

var person = {
name: "Toby Ho",
language: "javascript",
likes: ["node", "testem", "jazz"]
};

COFFEESCRIPT

person =
name: "Toby Ho"
language: "javascript"
likes: ["node", "testem", "jazz"]
Functions.
Functions in JS
function eat(){
console.log("eating");
};

var eat = function(){
console.log("eating");
};

DECLARATION

EXPRESSION
Functions in CS
COFFEESCRIPT
eat = ->
console.log "eating"

JAVASCRIPT
var eat;
eat = function() {
return console.log("eating");
};
Function Arguments
COFFEESCRIPT
eat = (options = {}) ->

JAVASCRIPT
var eat;
eat = function(options) {
if (options == null) {
options = {};
}
};
Function Context
JAVASCRIPT

COFFEESCRIPT

var person;
person = {
name: "Toby Ho",
energy: 0,
eat: function() {
return this.energy += 10;
}
};

> person.eat();
# 10

person =
name: "Toby Ho"
energy: 0
eat: ->
@energy += 10
Function Binding
JAVASCRIPT
var person;
person = {
name: "Toby Ho",
energy: 0,
work: function() {
var _this = this;
$("#stop").click(function() {
return _this.energy -= 20;
});
}
};

COFFEESCRIPT
person =
name: "Toby Ho"
energy: 0
work: ->
$("#stop").click =>
@energy -= 20
Function Binding
JAVASCRIPT
var person;

COFFEESCRIPT

person =
name: "Toby Ho"
person = {
energy: 0
name: "Toby Ho",
person = {
work: ->
energy: 0,
name: "Toby Ho",
$("#stop").click =>
energy: 0, work: function() {
@energy -= 20
return $("#stop").click((function(_this) {
work: function() {
return function() {
var _this = this;
return _this.energy -= 20;
$("#stop").click(function() {
};
return _this.energy -= 20;
})(this));
});
}
}
};
};
var person;
Function Splats
JAVASCRIPT
var person;

COFFEESCRIPT
person =
name: "Toby Ho"
dislikes: []
addDislikes: (args...) ->
@dislikes.push args...

person = {
name: "Toby Ho",
dislikes: [],
addDislikes: function() {
var args = [].slice.call(arguments);
return [].push.apply(this.dislikes, args);
}
};

> person.addDislikes(“frameworks”, “long plane rides”);
Ranges / Slicing
Array + String Slicing
COFFEESCRIPT

JAVASCRIPT

nums = [1..10]

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

nums[0...5]

nums.slice(0, 5);

[1,2,3,4,5]

nums[2..3] = [-3, -4]

[].splice.apply(nums,
[2,2].concat([-3, -4])
);

[1,2,-3,-4,5,
6,7,8,9,10]

"Toby Ho"[0..3]

"Toby Ho".slice(0, 4);

Toby
If, Else, Unless.
Flow Control
person =
name: "Toby Ho"
tired: true
work: ->
return if @tired
@program "javascript"
relax: ->

var person;

person = {
name: "Toby Ho",
tired: true,
work: function() {
if (this.tired) {
if moment.hour() > 10 then @read() else @tv()
return;
sleep: ->
}
@relax() unless @tired
return this.program("javascript");
},
relax: function() {
moment.hour() > 10 ? this.read() : this.tv();
},
sleep: function() {
if (!this.tired) {
return this.relax();
}
}
};

COFFEESCRIPT

JAVASCRIPT
Operators.
Operator Comparison
COFFEESCRIPT

JAVASCRIPT

is

===

true is true

isnt

!==

@name isnt "randall"

not

!

and

&&

or

||

true yes

on

true

false no

off

false

relax() if not working()
exercise() unless @tired and @sleepy

happy() if @happy or @energy

> 50
Existential
Operator.
Do You Really Exist?
person =
name: "Toby Ho"
energy: 0
address:
city: "Alpharetta"
state: "GA"
zip: 30307
phone: null
mail: -> "mailing..."

var _ref;
if ((_ref = person.address) != null) {
_ref.city;
}
if (typeof person.call === "function") {
person.call();
}

> person.address?.city

=>

Alpharetta

> person.phone?.cell

=>

undefined

> person.call?( )

=>

undefined

> person.call?( ) ? person.mail( )

=>

mailing...
String
Interpolation.
No more awkward ‘+’
JAVASCRIPT
"Hey, " + person.name + " is " + person.age + " years young.";

COFFEESCRIPT
"Hey, #{person.name} is #{person.age} years young."
Destructuring
Assignment.
Easy var extraction
person =
name: "Toby Ho"
energy: 0
address:
city: "Alpharetta"
state: "GA"
zip: 30307

COFFEESCRIPT
{name, energy, address} = person

JAVASCRIPT
var address, energy, name;
name
= person.name;
energy = person.energy;
address = person.address;
IIFE’s.
Module Pattern
JAVASCRIPT
App = (function() {
var privateVar = "can't get to me!";
var privateFn = function() {
return "can't invoke me either";
};
var obj = {
data: [],
props: {},
publicFn: function() {}
};
return obj;
})();

COFFEESCRIPT
App = do ->
privateVar = "can't get to me!"
privateFn = -> "can't invoke me either"
obj =
data: []
props: {}
publicFn: ->
return obj
Local Dependencies
JAVASCRIPT
(function($, BB) {
//reference jQuery as $
//reference Backbone as BB
})(jQuery, Backbone);

COFFEESCRIPT
do ($ = jQuery, BB = Backbone) ->
#reference jQuery as $
#reference Backbone as BB
Switch / Case.
...minus the case
COFFEESCRIPT
switch
when
when
when
else

state
"GA"
then "humid"
"WA"
then "rainy"
"AZ", "UT", "NV" then "dry"
"moderate"

JAVASCRIPT
switch (state) {
case "GA":
"humid";
break;
case "WA":
"rainy";
break;
case "AZ":
case "UT":
case "NV":
"dry";
break;
default:
"moderate";
}
No Control Expression
COFFEESCRIPT
energyLevel = switch
when @energy < 10 then "exhausted"
when @energy < 20 then "okay"
when @energy < 40 then "caffeinated"
else "bouncing off walls"

JAVASCRIPT
var energyLevel;
energyLevel = (function() {
switch (false) {
case !(this.energy < 10):
return "exhausted";
case !(this.energy < 20):
return "okay";
case !(this.energy < 40):
return "caffeinated";
default:
return "bouncing off walls";
}
}).call(this);
Loops /
Comprehensions.
For Loops
person =
name: "Toby Ho"
language: "javascript"
likes: ["node", "testem", "jazz"]

COFFEESCRIPT
for like, num in person.likes
console.log "#{num + 1}. #{like}"
var like, num, _i, _len, _ref;

=>

1. node
2. testem
3. jazz

JAVASCRIPT

_ref = person.likes;
for (num = _i = 0, _len = _ref.length; _i < _len; num = ++_i) {
like = _ref[num];
console.log("" + (num + 1) + ". " + like);
}
Property Iteration
heros = { john: "resig", ryan: "dahl" };

COFFEESCRIPT
for first, last of heros
console.log first, last

var first, last;

JAVASCRIPT

for (first in heros) {
last = heros[first];
console.log(first, last);
}

=>

john resig
ryan dahl
Array ‘in’ checking
person =
name: "Toby Ho"
dislikes: ["frameworks", "long plane rides"]

COFFEESCRIPT
if "coffeescript" in person.dislikes then "hater" else "friend :-)"

var __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; };
if (__indexOf.call(this.dislikes, "coffeescript") >= 0) {
"hater";
} else {
"friend :-)";
}

JAVASCRIPT
Comprehensions
{100 Objects}

COFFEESCRIPT
nums = (num: i for i in [1..100])

var i, nums;

=>

JAVASCRIPT

nums = (function() {
var _i, _results;
_results = [];
for (i = _i = 1; _i <= 100; i = ++_i) {
_results.push({
num: i
});
}
return _results;
})();

-------------------------[{
num: 1
},{
num: 2
}]
What was missed?

•
• Block Regular Expressions
Some Operators
•
• Chained Comparisons
Trailing Commas
•
• Reserved Words
Literate Coffeescript
•
• Classes, Inheritance, & Super
Block Strings
Debugging.
Syntax Errors
@PE.module "HeaderApp", +>

SUBLIME TEXT
Source Maps
CoffeeConsole
Literal CoffeeScript
Criticisms.
Dispelling the Myths

• Compiler Errors (WAT?)
• Performance
• Restrictions*
• Harder to Debug
• Less Readability
• You can skip learning JS
Lies,
Damned Lies,
& Statistics.
Productivity Gains
LINES OF
CODE

34,014

84,681

2.49X

CHARS

1,198,518

2,704,135

2.25X
S

CoffeeScript
The End
Brian Mann
@be_mann

Coffeescript: No really, it's just Javascript

  • 1.
    S CoffeeScript No really, it’sjust Javascript Brian Mann @be_mann Atlanta, GA
  • 2.
    What is CoffeeScript? •Exposes the good parts • Transpiles directly to JS • Removes / Adds new syntax • Enhances readability, and productivity • Clearly expresses intents
  • 3.
    Agenda • An EmotionalAssessment • Dive Into Features • Real World Experiences • Challenges / Critiques
  • 4.
  • 5.
    CoffeeScript is one ofthe most BEAUTIFUL / UGLY LOVED / HATED EMBRACED / FEARED LANGUAGES. / TOOLS. / SYNTAX.
  • 6.
  • 7.
  • 8.
  • 9.
    Why the hate? •CoffeeScript looks different • CoffeeScript acts different
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
    Before we begin • •No more commas • Optional parenthesis • Optional curly braces • White space sensitive No more semi-colons ; , () {}
  • 18.
  • 19.
    Vars are longgone var count, increment; JAVASCRIPT count = 0; increment = function() { var total; count += 1; return total = "The total is: " + count; }; count = 0 COFFEESCRIPT increment = -> count += 1 total = "The total is: " + count
  • 20.
  • 21.
  • 22.
    Objects Simplified JAVASCRIPT var person= { name: "Toby Ho", language: "javascript", likes: ["node", "testem", "jazz"] }; COFFEESCRIPT person = name: "Toby Ho" language: "javascript" likes: ["node", "testem", "jazz"]
  • 23.
  • 24.
    Functions in JS functioneat(){ console.log("eating"); }; var eat = function(){ console.log("eating"); }; DECLARATION EXPRESSION
  • 25.
    Functions in CS COFFEESCRIPT eat= -> console.log "eating" JAVASCRIPT var eat; eat = function() { return console.log("eating"); };
  • 26.
    Function Arguments COFFEESCRIPT eat =(options = {}) -> JAVASCRIPT var eat; eat = function(options) { if (options == null) { options = {}; } };
  • 27.
    Function Context JAVASCRIPT COFFEESCRIPT var person; person= { name: "Toby Ho", energy: 0, eat: function() { return this.energy += 10; } }; > person.eat(); # 10 person = name: "Toby Ho" energy: 0 eat: -> @energy += 10
  • 28.
    Function Binding JAVASCRIPT var person; person= { name: "Toby Ho", energy: 0, work: function() { var _this = this; $("#stop").click(function() { return _this.energy -= 20; }); } }; COFFEESCRIPT person = name: "Toby Ho" energy: 0 work: -> $("#stop").click => @energy -= 20
  • 29.
    Function Binding JAVASCRIPT var person; COFFEESCRIPT person= name: "Toby Ho" person = { energy: 0 name: "Toby Ho", person = { work: -> energy: 0, name: "Toby Ho", $("#stop").click => energy: 0, work: function() { @energy -= 20 return $("#stop").click((function(_this) { work: function() { return function() { var _this = this; return _this.energy -= 20; $("#stop").click(function() { }; return _this.energy -= 20; })(this)); }); } } }; }; var person;
  • 30.
    Function Splats JAVASCRIPT var person; COFFEESCRIPT person= name: "Toby Ho" dislikes: [] addDislikes: (args...) -> @dislikes.push args... person = { name: "Toby Ho", dislikes: [], addDislikes: function() { var args = [].slice.call(arguments); return [].push.apply(this.dislikes, args); } }; > person.addDislikes(“frameworks”, “long plane rides”);
  • 31.
  • 32.
    Array + StringSlicing COFFEESCRIPT JAVASCRIPT nums = [1..10] nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; nums[0...5] nums.slice(0, 5); [1,2,3,4,5] nums[2..3] = [-3, -4] [].splice.apply(nums, [2,2].concat([-3, -4]) ); [1,2,-3,-4,5, 6,7,8,9,10] "Toby Ho"[0..3] "Toby Ho".slice(0, 4); Toby
  • 33.
  • 34.
    Flow Control person = name:"Toby Ho" tired: true work: -> return if @tired @program "javascript" relax: -> var person; person = { name: "Toby Ho", tired: true, work: function() { if (this.tired) { if moment.hour() > 10 then @read() else @tv() return; sleep: -> } @relax() unless @tired return this.program("javascript"); }, relax: function() { moment.hour() > 10 ? this.read() : this.tv(); }, sleep: function() { if (!this.tired) { return this.relax(); } } }; COFFEESCRIPT JAVASCRIPT
  • 35.
  • 36.
    Operator Comparison COFFEESCRIPT JAVASCRIPT is === true istrue isnt !== @name isnt "randall" not ! and && or || true yes on true false no off false relax() if not working() exercise() unless @tired and @sleepy happy() if @happy or @energy > 50
  • 37.
  • 38.
    Do You ReallyExist? person = name: "Toby Ho" energy: 0 address: city: "Alpharetta" state: "GA" zip: 30307 phone: null mail: -> "mailing..." var _ref; if ((_ref = person.address) != null) { _ref.city; } if (typeof person.call === "function") { person.call(); } > person.address?.city => Alpharetta > person.phone?.cell => undefined > person.call?( ) => undefined > person.call?( ) ? person.mail( ) => mailing...
  • 39.
  • 40.
    No more awkward‘+’ JAVASCRIPT "Hey, " + person.name + " is " + person.age + " years young."; COFFEESCRIPT "Hey, #{person.name} is #{person.age} years young."
  • 41.
  • 42.
    Easy var extraction person= name: "Toby Ho" energy: 0 address: city: "Alpharetta" state: "GA" zip: 30307 COFFEESCRIPT {name, energy, address} = person JAVASCRIPT var address, energy, name; name = person.name; energy = person.energy; address = person.address;
  • 43.
  • 44.
    Module Pattern JAVASCRIPT App =(function() { var privateVar = "can't get to me!"; var privateFn = function() { return "can't invoke me either"; }; var obj = { data: [], props: {}, publicFn: function() {} }; return obj; })(); COFFEESCRIPT App = do -> privateVar = "can't get to me!" privateFn = -> "can't invoke me either" obj = data: [] props: {} publicFn: -> return obj
  • 45.
    Local Dependencies JAVASCRIPT (function($, BB){ //reference jQuery as $ //reference Backbone as BB })(jQuery, Backbone); COFFEESCRIPT do ($ = jQuery, BB = Backbone) -> #reference jQuery as $ #reference Backbone as BB
  • 46.
  • 47.
    ...minus the case COFFEESCRIPT switch when when when else state "GA" then"humid" "WA" then "rainy" "AZ", "UT", "NV" then "dry" "moderate" JAVASCRIPT switch (state) { case "GA": "humid"; break; case "WA": "rainy"; break; case "AZ": case "UT": case "NV": "dry"; break; default: "moderate"; }
  • 48.
    No Control Expression COFFEESCRIPT energyLevel= switch when @energy < 10 then "exhausted" when @energy < 20 then "okay" when @energy < 40 then "caffeinated" else "bouncing off walls" JAVASCRIPT var energyLevel; energyLevel = (function() { switch (false) { case !(this.energy < 10): return "exhausted"; case !(this.energy < 20): return "okay"; case !(this.energy < 40): return "caffeinated"; default: return "bouncing off walls"; } }).call(this);
  • 49.
  • 50.
    For Loops person = name:"Toby Ho" language: "javascript" likes: ["node", "testem", "jazz"] COFFEESCRIPT for like, num in person.likes console.log "#{num + 1}. #{like}" var like, num, _i, _len, _ref; => 1. node 2. testem 3. jazz JAVASCRIPT _ref = person.likes; for (num = _i = 0, _len = _ref.length; _i < _len; num = ++_i) { like = _ref[num]; console.log("" + (num + 1) + ". " + like); }
  • 51.
    Property Iteration heros ={ john: "resig", ryan: "dahl" }; COFFEESCRIPT for first, last of heros console.log first, last var first, last; JAVASCRIPT for (first in heros) { last = heros[first]; console.log(first, last); } => john resig ryan dahl
  • 52.
    Array ‘in’ checking person= name: "Toby Ho" dislikes: ["frameworks", "long plane rides"] COFFEESCRIPT if "coffeescript" in person.dislikes then "hater" else "friend :-)" var __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; }; if (__indexOf.call(this.dislikes, "coffeescript") >= 0) { "hater"; } else { "friend :-)"; } JAVASCRIPT
  • 53.
    Comprehensions {100 Objects} COFFEESCRIPT nums =(num: i for i in [1..100]) var i, nums; => JAVASCRIPT nums = (function() { var _i, _results; _results = []; for (i = _i = 1; _i <= 100; i = ++_i) { _results.push({ num: i }); } return _results; })(); -------------------------[{ num: 1 },{ num: 2 }]
  • 54.
    What was missed? • •Block Regular Expressions Some Operators • • Chained Comparisons Trailing Commas • • Reserved Words Literate Coffeescript • • Classes, Inheritance, & Super Block Strings
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
    Dispelling the Myths •Compiler Errors (WAT?) • Performance • Restrictions* • Harder to Debug • Less Readability • You can skip learning JS
  • 62.
  • 63.
  • 64.