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