COFFEESCRIPT:
THE GOOD PARTS
rule #1: it's just javascript
# You write this:
do ->
str = "hello world!"
alert str
// Browser sees this:
(function() {
var str = "hello world!";
alert(str);
})();
Your first cup: Basic concepts
# No need for var, no semicolons, scoping becomes intuitive
num = 12
var num;
num = 12;
# Functions resemble C# lambda expressions
foo = (x, y) -> x + y
foo = function(x, y) {
return x + y;
}
# Whitespace is significant
foo = ->
alert "hello world"
x = 15
foo = function() {
return alert("hello world");
}
x = 15;
# var, return, (), [], and ; are often implied
foo bar
opts =
color: "red"
size:
height: 45
width: 150
success: ->
console.log "ok"
foo(bar);
var opts = {
color: "red",
size: {
height: 45,
width: 150
},
success: function() {
console.log("ok");
}
};
# Syntactic shortcuts
x = (y, z) ->
y + z
var x = function(y, z) {
return y + z;
};
[a, b, c] = arr
{x, y, z} = obj
var a, b, c, x, y, z;
a = arr[0], b = arr[1], c = arr[2];
x = obj.x, y = obj.y, z = obj.z;
{
poet: {
name,
address: [street, city]
}
} = futurists
var name = futurists.poet.name,
street = futurists.poet.address[0],
city = futurists.poet.address[1];
# Designed to look more like a natural language
if light is on then alert "on"
else alert "off"
if (light === true) {
alert("on");
} else {
alert("off");
}
x = 12 unless y
if (!y) {
x = 12;
}
x = if y then 12 else 15
if (y) {
x = 12;
} else {
x = 15;
}
# Designed to reduce common mistakes
if x is 4
if x == 4
if x?
if (x === 4)
if (x === 4)
if (typeof x !== "undefined"
&& x !== null)
Have some sugar with your syntax
# this == @ == this
this.foo()
@.foo()
@foo()
this.foo();
this.foo();
this.foo();
# JavaScript's missing string formatter
alert "#{ a }...#{ b + c }...#{ d }"
alert(a + "..." + (b + c) + "..." + d);
# IIFEs, too
do ($ = jQuery) ->
x = 5
$('div').on 'click', ->
$(@).html x
(function($) {
var x = 5;
$('div').on('click', function() {
$(this).html(x);
});
})(jQuery);
# Loop over collections without writing a novel
alert num for num in [1, 2, 3]
var _arr = [1, 2, 3];
for (var i = 0; i < _arr.length; i++) {
alert(_arr[i]);
}
alert num, i for num, i in {a, b, c}
var _obj = {a: a, b: b, c: c};
for (var i = 0; i < _obj.length; i++) {
alert(_obj[i], i);
}
# Fill and consume lists easily
x = [1..7]
y = [1...7]
plus3 = (z + 3 for z in [1..5])
var x = [1, 2, 3, 4, 5, 6, 7];
var y = [1, 2, 3, 4, 5, 6];
var _arr = [1, 2, 3, 4, 5], plus3 = [];
for (var i = 0; i < _arr.length; i++) {
plus3.push(_arr[i] + 3);
}
# Even get a little cray-cray
[a, b..., c] = text.split " "
var _arr = text.split(" ");
a = _arr[0];
b = _arr.length
? _arr.slice(1, _arr.length - 1)
: [];
c = _arr[_arr.length - 1];
# Multi-line strings!
str = """
the quick
brown
fox
"""
str = "the quick \nbrown \nfox";
# Multi-line regex with comments!
regex = ///
\b #word break
limit-
(\d+) #capture this number
///i
regex = /\blimit-(\d+)/i
# Multi-line comments! Okay, not new.
###
But putting comments
in regular expressions
is pretty cool, right?
###
/*
Free haiku with DevSession
*/
Splat...variadic functions made easy
# Turn named parameters into arrays
min = (list...) ->
curr = 0
curr = x for x in list when x < curr
curr
alert min a, b, c, d, e
var min = function() {
var i, curr = 0, list = Array.prototype.apply(arguments);
for (i = 0; i < list.length; i++) {
if (list[i] < curr) {
curr = list[i];
}
}
return curr;
};
alert(min(a, b, c, d, e));
# Turn arrays into named parameters
date = (year, month, day) ->
"#{ month }/#{ day }/#{ year }"
arr = [1999, 12, 31]
alert date arr...
var date = function(year, month, day) {
return month + "/" + day + "/" + year;
};
var arr = [1999, 12, 31]
alert(date.apply(null, arr));
Other sweet ingredients
# Compile-time context binding operator
foo = (name) =>
@name = name
var __this = this;
var foo = function (name) {
__this.name = name;
};
# Automatic property binding (useful for constructors)
foo = (a, b) ->
[@a, @b] = [a, b]
var foo = function (a, b) {
this.a = a;
this.b = b;
};
foo = (@a, @b) ->
var foo = function (a, b) {
this.a = a;
this.b = b;
};
//yes, it does the same thing
foo = (options) ->
{@a, @b, @c} = options
var foo = function (options) {
this.a = options.a;
this.b = options.b;
this.c = options.c;
};
# Chained comparisons
healthy = 200 > cholesterol > 60
healthy = (200 > cholesterol && cholesterol > 60);
# New, improved switch blocks
switch day
when "Mon" then go work
when "Tue" then go relax
when "Thu" then go iceFishing
when "Fri", "Sat"
if day is bingoDay
go bingo
go dancing
when "Sun" then go church
else go work
grade = switch
when score < 60 then 'F'
when score < 70 then 'D'
when score < 80 then 'C'
when score < 90 then 'B'
else 'A'
# And my favorite, the existential operator
a = true if b? and not c?
if ((b != null) && (c == null)) {
a = true;
}
options ?= {}
if (options == null) {
options = {};
}
foo?.bar?.baz?().quux()
if (foo !== null
&& foo.bar != null
&& typeof foo.bar.baz === "function") {
x = foo.bar.baz().quux();
} else {
x = void(0);
}
And a bunch of other crazy stuff
# Classes and inheritance
class Animal
constructor: (@name) ->
move: (meters) ->
alert @name + " moved #{meters}m."
class Snake extends Animal
move: ->
alert "Slithering..."
super 5
# Aliases
is, ==
inst, !=
not, !
and, &&
or, ||
true, yes, on
false, no, off
x unless y else z
@, this
of
in
a ** b
a // b
a %% b
===
!==
!
&&
||
true
false
!y ? x : z
this
in
//no true JS equivalent
Math.pow(a, b)
Math.floor(a / b)
(a % b + b) % b
Wait! I need decaf
# You can still embed plain JavaScript
if `x == y` then do z
if (x == y) {
z();
}
But I still wish it had...
# Operators for run-time context binding
x = foo <- a, b, c
y = foo<a> b, c
var x = foo.call(a, b, c)
var y = foo.bind(a)(b, c);
# Option to force strict mode
alert "hello world!"
(function () {
"use strict";
alert("hello world!");
});
# Better defense against this silliness
if x == y then foo() #good
if x is y then foo() #better
if x = y then foo() #Why is this even
#allowed?
if (x === y) { foo(); }
if (x === y) { foo(); }
if (x = y) { foo(); }
Coffee goes with everything
# Editors and development tools
- Web Essentials for Visual Studio
- jsFiddle
- CoffeeScript.org
- Cassette
- Js2Coffee
# Add-ons and related projects
- IcedCoffeeScript
- CoffeeKup
CoffeeScript: The Good Parts
By Justin Morgan
CoffeeScript: The Good Parts
- 399