why (i think) coffeescript is awesome
DESCRIPTION
Slides for a CoffeeScript presentation at Ruby on Rails Sydney user group on May 8.TRANSCRIPT
Why CoffeeScript IsAwesome*
*IMO@jocranfordTuesday, 8 May 12
How CoffeeScript works
file.js webpage.htmlCompilefile.coffee
Include via <script>
Tuesday, 8 May 12
Getting started was EASY
Tuesday, 8 May 12
Installation with Node Package Manager
Tuesday, 8 May 12
Compiling a Coffee Script File
Tuesday, 8 May 12
Compiling Multiple Coffee Script Files
Tuesday, 8 May 12
Web Workbench Visual Studio Plugin
Tuesday, 8 May 12
Autogeneration of JavaScript
Tuesday, 8 May 12
Errors in Output Window
Tuesday, 8 May 12
Basic Syntax
Tuesday, 8 May 12
var myPresentation = { title: "CoffeeScript", when: { day: "8 May 2012", time: "6:30pm" }};
Object Definition
Tuesday, 8 May 12
var myPresentation = { title: "CoffeeScript", when: { day: "8 May 2012", time: "6:30pm" }};
Object Definition
myPresentation = subject: "CoffeeScript” when: day: "8 May 2012" time: "6:30pm"
Tuesday, 8 May 12
var myPresentation = { title: "CoffeeScript", when: { day: "8 May 2012", time: "6:30pm" }};
Object Definition
myPresentation = subject: "CoffeeScript” when: day: "8 May 2012" time: "6:30pm"
Tuesday, 8 May 12
Function Definitionfunction startPresentation(subject) { alert("A presentation about " + subject + " is now starting!");}
var startPresentation = function(subject) { alert("A presentation about " + subject + " is now starting!");};
startPresentation("JavaScript");
Tuesday, 8 May 12
Function Definitionfunction startPresentation(subject) { alert("A presentation about " + subject + " is now starting!");}
var startPresentation = function(subject) { alert("A presentation about " + subject + " is now starting!");};
startPresentation("JavaScript");
startPresentation = (subject) -> alert "A presentation about " + subject + " is now starting!"
startPresentation "CoffeeScript"
Tuesday, 8 May 12
Function Definitionfunction startPresentation(subject) { alert("A presentation about " + subject + " is now starting!");}
var startPresentation = function(subject) { alert("A presentation about " + subject + " is now starting!");};
startPresentation("JavaScript");
startPresentation = (subject) -> alert "A presentation about " + subject + " is now starting!"
startPresentation "CoffeeScript"
Tuesday, 8 May 12
Operators
CoffeeScript JavaScript
is ===
isnt !==
not !
and &&
or ||
of in
Tuesday, 8 May 12
Syntactic Sugar
Tuesday, 8 May 12
String Interpolation
var description = "This is a talk about " + myPresentation.subject + " by " + myPresentation.presenter + ". It will start at " + myPresentation.startTime + " and finish by " + myPresentation.endTime;
Tuesday, 8 May 12
String Interpolation
var description = "This is a talk about " + myPresentation.subject + " by " + myPresentation.presenter + ". It will start at " + myPresentation.startTime + " and finish by " + myPresentation.endTime;
description = "This is a talk about #{myPresentation.subject} by #{myPresentation.presenter}. It will start at #{myPresentation.startTime} and finish by #{myPresentation.endTime}"
Tuesday, 8 May 12
String Interpolation
var description = "This is a talk about " + myPresentation.subject + " by " + myPresentation.presenter + ". It will start at " + myPresentation.startTime + " and finish by " + myPresentation.endTime;
description = "This is a talk about #{myPresentation.subject} by #{myPresentation.presenter}. It will start at #{myPresentation.startTime} and finish by #{myPresentation.endTime}"
Tuesday, 8 May 12
@ replaces thisvar Presentation = function(title, presenter) {
this.getHeadline = function() { return title + " by " + presenter; };
this.showHeadline = function() { alert(this.getHeadline()); };
};
Tuesday, 8 May 12
@ replaces this
class Presentation
constructor: (@title, @presenter) ->
getHeadline: -> "#{@title} by #{@presenter}"
showHeadline: -> alert(@getHeadline())
var Presentation = function(title, presenter) {
this.getHeadline = function() { return title + " by " + presenter; };
this.showHeadline = function() { alert(this.getHeadline()); };
};
Tuesday, 8 May 12
@ replaces this
class Presentation
constructor: (@title, @presenter) ->
getHeadline: -> "#{@title} by #{@presenter}"
showHeadline: -> alert(@getHeadline())
var Presentation = function(title, presenter) {
this.getHeadline = function() { return title + " by " + presenter; };
this.showHeadline = function() { alert(this.getHeadline()); };
};
Tuesday, 8 May 12
functions return the last value
function add(x, y) { return x + y;}
Tuesday, 8 May 12
functions return the last value
function add(x, y) { return x + y;}
add = (x, y) -> x + y
Tuesday, 8 May 12
functions return the last value
function add(x, y) { return x + y;}
add = (x, y) -> x + y
Tuesday, 8 May 12
Conditionals return automaticallyvar textColor;
if (result === "failed") { textColor = "red";} else if (result === "not run") { textColor = "yellow";} else { textColor = "green";}
Tuesday, 8 May 12
Conditionals return automaticallyvar textColor;
if (result === "failed") { textColor = "red";} else if (result === "not run") { textColor = "yellow";} else { textColor = "green";}
textColor = if result is "failed" "red" else if result is "not run" "yellow" else "green"
Tuesday, 8 May 12
Conditionals return automaticallyvar textColor;
if (result === "failed") { textColor = "red";} else if (result === "not run") { textColor = "yellow";} else { textColor = "green";}
textColor = if result is "failed" "red" else if result is "not run" "yellow" else "green"
Tuesday, 8 May 12
Protection from Evil
Tuesday, 8 May 12
In JavaScript, variables are global by default
var tonightsPresentations = [ "CoffeeScript", "i18n", "Rails Conf"];
var whoopsie = function() { tonightsPresentations = []; return tonightsPresentations;}
Tuesday, 8 May 12
In CoffeeScript, they are automatically scoped
tonightsPresentations = [ "CoffeeScript", "i18n", "Rails Conf"]
whoopsie = ->! tonightsPresentations = []! tonightsPresentations
var tonightsPresentations = [ "CoffeeScript", "i18n", "Rails Conf"];
var whoopsie = function() { teamHugPresentationList = []; return teamHugPresentationList;}
Tuesday, 8 May 12
WTF ...
0 == "" and 0 =="0" are both TRUE ... but "" == "0" is NOT!
false == "0" is TRUE ... but false == "false" is NOT!
Tuesday, 8 May 12
WTF ...
0 == "" and 0 =="0" are both TRUE ... but "" == "0" is NOT!
false == "0" is TRUE ... but false == "false" is NOT!
is => ===
isnt => !==
== -> ===
Tuesday, 8 May 12
With
;Reserved Keywords
✗
✗
✗
Tuesday, 8 May 12
Consistency
Tuesday, 8 May 12
var Presentation = function(title, presenter) { return { getHeadline: function() { return title + " by " + presenter; } }};
var myPresentation = Presentation("CoffeeScript", "Jo Cranford");
Example 1
Tuesday, 8 May 12
var Presentation = function(title, presenter) {
this.getHeadline = function() { return title + " by " + presenter; };
};
var myPresentation = new Presentation("CoffeeScript", "Jo Cranford");
Example 2
Tuesday, 8 May 12
var Presentation = function(title, presenter) { this.title = title; this.presenter = presenter;};
Presentation.prototype.getHeadline = function() { return this.title + " by " + this.presenter;};
var myPresentation = new Presentation("CoffeeScript", "Jo Cranford");
Example 3
Tuesday, 8 May 12
CoffeeScript
class Presentation
constructor: (@title, @presenter) ->
getHeadline: -> @title + " " + @presenter
Tuesday, 8 May 12
Less Code
Tuesday, 8 May 12
Average Lines Of Code
0
10
20
30
40
JavaScript CoffeeScript
1.8X
Tuesday, 8 May 12
For Loopvar i, weatherInCities;
weatherInCities = [];
for(i = 0; i < listOfCities.length; i++) {
! var city = listOfCities[i];
! weatherInCities.push(city.name + ":" + city.weather);
}
Tuesday, 8 May 12
For Loopvar i, weatherInCities;
weatherInCities = [];
for(i = 0; i < listOfCities.length; i++) {
! var city = listOfCities[i];
! weatherInCities.push(city.name + ":" + city.weather);
}
weatherInCities = (("#{city.name}: #{city.weather}") for city in listOfCities)
Tuesday, 8 May 12
For Loopvar i, weatherInCities;
weatherInCities = [];
for(i = 0; i < listOfCities.length; i++) {
! var city = listOfCities[i];
! weatherInCities.push(city.name + ":" + city.weather);
}
weatherInCities = (("#{city.name}: #{city.weather}") for city in listOfCities)
Tuesday, 8 May 12
var objectToString = function (obj) {! var key, val, _results;! _results = [];
! for (key in obj) {! ! if (!obj.hasOwnProperty(key)) continue;! ! val = obj[key];! ! if (val !== null) _results.push(key + ":" + val);! }! return _results.join(",");};
For “Own” Loop
Tuesday, 8 May 12
var objectToString = function (obj) {! var key, val, _results;! _results = [];
! for (key in obj) {! ! if (!obj.hasOwnProperty(key)) continue;! ! val = obj[key];! ! if (val !== null) _results.push(key + ":" + val);! }! return _results.join(",");};
For “Own” Loop
objectToString = (obj) ->
! ("#{key}:#{val}" for own key, val of obj when val isnt null).join(“,")
Tuesday, 8 May 12
var objectToString = function (obj) {! var key, val, _results;! _results = [];
! for (key in obj) {! ! if (!obj.hasOwnProperty(key)) continue;! ! val = obj[key];! ! if (val !== null) _results.push(key + ":" + val);! }! return _results.join(",");};
For “Own” Loop
objectToString = (obj) ->
! ("#{key}:#{val}" for own key, val of obj when val isnt null).join(“,")
Tuesday, 8 May 12
var Region = function(states) {! this.states = states;};
Region.prototype.findStatesBeginningWith = function(letter) {! var matchingStates = []; for (var i = 0;i < this.states.length; i++) {! ! state = this.states[i];! ! if (state.substr(0,1) === letter) {! ! ! matchingStates.push(state)! ! }! }! return matchingStates;};
Constructor - JavaScript
Tuesday, 8 May 12
class Region
constructor: (@states) ->
findStatesBeginningWith: (letter) ->
state for state in @states when state.substr(0,1) is letter
Constructor - CoffeeScript
Tuesday, 8 May 12
class Region
constructor: (@states) ->
findStatesBeginningWith: (letter) ->
state for state in @states when state.substr(0,1) is letter
Constructor - CoffeeScript
Tuesday, 8 May 12
var Clickable = function (baseElement) {
! var that = this;
! this.displayAlert = function() {
! ! alert("You just clicked me!");
! };
! $(baseElement).click(that.displayAlert);
};
this and that
Tuesday, 8 May 12
var Clickable = function (baseElement) {
! var that = this;
! this.displayAlert = function() {
! ! alert("You just clicked me!");
! };
! $(baseElement).click(that.displayAlert);
};
this and that
Tuesday, 8 May 12
var Clickable = function (baseElement) {
! var that = this;
! this.displayAlert = function() {
! ! alert("You just clicked me!");
! };
! $(baseElement).click(that.displayAlert);
};
this and that
class window.Clickable
constructor: (@baseElement) ->
$(@baseElement).click(@displayAlert)
displayAlert: =>
window.alert("You just clicked me!")
Tuesday, 8 May 12
var Clickable = function (baseElement) {
! var that = this;
! this.displayAlert = function() {
! ! alert("You just clicked me!");
! };
! $(baseElement).click(that.displayAlert);
};
this and that
class window.Clickable
constructor: (@baseElement) ->
$(@baseElement).click(@displayAlert)
displayAlert: =>
window.alert("You just clicked me!")
Tuesday, 8 May 12
Pattern Matching – Reading an Object
var london = { lat: 51.5171, lng: 0.1062};
var lat = london.lat;var lng = london.lng;
Tuesday, 8 May 12
Pattern Matching – Reading an Object
var london = { lat: 51.5171, lng: 0.1062};
var lat = london.lat;var lng = london.lng;
london = lat: 51.5171 lng: 0.1062
{lat,lng} = london
Tuesday, 8 May 12
Pattern Matching
var london = { lat: 51.5171, lng: 0.1062};
var lat = london.lat;var lng = london.lng;
london = lat: 51.5171 lng: 0.1062
{lat,lng} = london
Tuesday, 8 May 12
Pattern Matching
doSomethingWithPoint = ({lat,lng}) -> console.log(lat, lng);
doSomethingWithPoint london
createPoint = (lat, lng) -> { lat, lng }
Tuesday, 8 May 12
Existing libraries just work
Tuesday, 8 May 12
JQuery$(document).ready(function() { var tip = $("#js-tooltip");
if (!tip.hasClass("hidden")) { tip.addClass("hidden"); }});
Tuesday, 8 May 12
$(document).ready(function() { var tip = $("#js-tooltip");
if (!tip.hasClass("hidden")) { tip.addClass("hidden"); }});
JQuery
$(document).ready(-> tip = $ "#coffee-tooltip"
tip.addClass "hidden" unless tip.hasClass "hidden")
Tuesday, 8 May 12
$(document).ready(function() { var tip = $("#js-tooltip");
if (!tip.hasClass("hidden")) { tip.addClass("hidden"); }});
JQuery
$(document).ready(-> tip = $ "#coffee-tooltip"
tip.addClass "hidden" unless tip.hasClass "hidden")
Tuesday, 8 May 12
Easy to Test with Jasmine
Tuesday, 8 May 12
describe("The Game Object", function() {
it("should have a score of 0 if I knock down no skittles", function() { var game = new Game(); game.roll(0); var score = game.score(); expect(score).toBe(0); });});
Jasmine Test
Tuesday, 8 May 12
describe("The Game Object", function() {
it("should have a score of 0 if I knock down no skittles", function() { var game = new Game(); game.roll(0); var score = game.score(); expect(score).toBe(0); });});
describe "The Game Object", ->
it "should have a score of 0 if I knock down no skittles", -> game = new Game() game.roll(0) score = game.score() expect(score).toBe 0
Jasmine Test
Tuesday, 8 May 12
Clean, Efficient, Easy to Read JavaScript
Tuesday, 8 May 12
class Presentation
constructor: (@title, @presenter) ->
getHeadline: -> "#{@title} #{@presenter}"
Tuesday, 8 May 12
(function() { var Presentation;
Presentation = (function() {
Presentation.name = 'Presentation';
function Presentation(title, presenter) { this.title = title; this.presenter = presenter; }
Presentation.prototype.getHeadline = function() { return this.title + " " + this.presenter; };
return Presentation;
})();
}).call(this);
Tuesday, 8 May 12
(function() { var Presentation;
Presentation = (function() {
Presentation.name = 'Presentation';
function Presentation(title, presenter) { this.title = title; this.presenter = presenter; }
Presentation.prototype.getHeadline = function() { return this.title + " " + this.presenter; };
return Presentation;
})();
}).call(this);
Tuesday, 8 May 12
Of course, it’s not perfect
Tuesday, 8 May 12
It IS an additional step
Debugging
Shouldn't we just write good JavaScript?
Should we even be writing object oriented JavaScript?
Tuesday, 8 May 12
References
• http://coffeescript.org/• http://www.weave.de/wp-content/uploads/2012/01/The-Little-Book-on-
Coffee-Script.pdf• http://pragprog.com/magazines/2011-05/a-coffeescript-intervention• http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/• http://css.dzone.com/articles/source-maps-coffeescript• http://www.quora.com/CoffeeScript/What-are-disadvantages-of-using-
CoffeeScript• http://www.readwriteweb.com/hack/2011/01/interview-coffeescript-jeremy-
ashkenas.php• http://rzrsharp.net/2011/06/27/what-does-coffeescripts-do-do.html• http://stackoverflow.com/questions/643542/doesnt-javascript-support-
closures-with-local-variables/643664#643664• http://yannesposito.com/Scratch/en/blog/2011-01-03-Why-I-sadly-won-t-
use-coffeescript/
Tuesday, 8 May 12