Coffee Script

http://webapplog.com/coffeescript-the-good-parts/ - done reading except for the video
https://www.youtube.com/watch?v=WX5Y6Dq1OHE
https://speakerdeck.com/azat/coffeescript-the-good-parts
http://www.infoq.com/presentations/coffeescript-lessons
http://autotelicum.github.io/Smooth-CoffeeScript/SmoothCoffeeScript.html
http://www.netmagazine.com/features/10-good-reasons-use-coffeescript
http://webapplog.com/coffeescript-the-good-parts-write-better-javascript/
http://webapplog.com/coffeescript-fundamentals-the-better-javascript/
http://www.sitepoint.com/accelerate-javascript-development-coffeescript/
http://autotelicum.github.io/Smooth-CoffeeScript/SmoothCoffeeScript.html
http://www.sitepoint.com/practical-coffeescript-tic-tac-toe
https://medium.com/@sagish/node-with-benefits-using-coffeescript-in-your-stack-e9754bf58668
http://jspro.com/coffeescript/list-processing-in-coffeescript/
http://stackoverflow.com/questions/12874942/adding-typescript-to-coffeescript
https://github.com/raganwald/homoiconic/blob/master/2011/12/jargon.md
http://news.ycombinator.com/item?id=3840718 - doesn't matter
http://net.tutsplus.com/articles/interviews/should-you-learn-coffeescript/ - doesn't matter
http://coffeescript.org/
http://js2coffee.org/

Important:
http://webapplog.com/coffeescript-quirks/ - done reading

http://webapplog.com/understanding-fat-arrows-in-coffeescript/ - done reading
http://www.tuicool.com/articles/7j2eIn - done reading
http://net.tutsplus.com/tutorials/javascript-ajax/writing-hubot-plugins-with-coffeescript/ - done reading

Debugging

What is CoffeeScript?

CoffeeScript is compile language and is a compiler. It allows human programmers to write code in a supposedly easy-to-understand form. The compiler then translates the code into JavaScript. With CoffeeScript, programmers do not need to bother with curly braces. Spacing and indentation is used to signify the opening and closing of various sections. If the indentations are removed, the CoffeeScript compiler returns an error because it does not know which statements go with the if statement.

How can we install CoffeeScript?

gem install coffee-script  // For Ruby on Rails
npm install -g coffee-script // Node

How can we compile a source file?

coffee -c myfile.coffee
coffee -wc myfile.coffee  // Automatically watch the file for changes and recompile the file if necessary

When the compiler is used, it creates a new JavaScript file with the same name (ex. myfile.js).

Why should we use CoffeeScript?

  • With CoffeeScript, the coder does not need to bother with the curly braces as are found in the JavaScript language. Instead, the spacing and indentation is used to signify the opening and closing of various sections.

Is CoffeeScript a compile language?

Yes. The CoffeeScript compiler can eliminate some of the trouble normally associated with compiling. If the watch option (-w) is used, the compiler will watch for the file to be saved and automatically compile it each time it is saved.

What are the differences between JavaScript and CoffeeScript?

  • No semi-colons
  • No var. The var keyword is no longer required with CoffeeScript.
  • No curly braces.

Object in CoffeeScript:

book =
  title: "Ready Player One"
  date: "10/16/2011"
  references:
    games: ["Street Fighter", "Pac-Man"]
    music: ["Oingo Boingo", "Men Without Hats"]
    movies: ["Back To The Future", "The Last Starfighter"]

JavaScript code:

book = {
    title: 'Ready Player One',
    date: '10/16/2011',
    references: {
        games: ['Street Fighter', 'Pac-Man'],
        music: ['Oingo Boingo', 'Men Without Hats'],
        movies: ['Back To The Future', 'The Last Starfighter']
    }
}

CoffeeScript function:

openGate = (key) ->
  gates =
    Copper: "You opened the Copper Gate"
    Jade: "You opened the Jade Gate"
    Crystal: "You opened the Crystal Gate"

  gates[key] | "Your key is invalid"
openGate "Jade"

JavaScript code:

function openGate(key) {
    var gates = {
        'Copper': 'You opened the Copper Gate',
        'Jade': 'You opened the Jade Gate',
        'Crystal': 'You opened the Crystal Gate'
    };
    return gates[key] || 'Your key is invalid'
}

openGate('Jade')

JavaScript:

myFunction = function (arg1, arg2)  {
};

CoffeeScript:

myFunction = (arg1, arg2) ->;

JavaScript:

myFunction = function (arg1, arg2) {
    return arg1 + arg2;
}

CoffeeScript:

myFunction = (arg1, arg2) -> arg1 + arg2;

Notice that no explicit return is needed in CoffeeScript functions. The CoffeeScript compiler always returns the value of the last statement

JavaScript:

var instrument, i, len, ref;
ref = ["piano", "violin", "guitar"];
for (i = 0, len = ref.lenth; i < len; i++) {
    play(ref[i]);
}

CoffeeScript:

play instrument for instrument in ["piano", "violin", "guitar"];

CoffeeScript also makes it easy to go through a loop while excluding a certain item:

instruments = ["piano", "violin", "guitar", "flute", "drum" ]
play instrument for instrument in instruments when instrument isnt flute

The switch statement in JavaScript requires the programmer to insert appropriate break statement. If the programmer accidentally leave out a break statement, he may have to spend hours to debug the problem. The switch statement in CoffeeScript does not requires the programmer to insert break statements.

JavaScript:

switch (food) {
    case "fish":
        cooke(bake);
        break;

    case "steak" :
        cook(grill)
        break;
    default:
        cook(pan);
}

CoffeeScript:

switch food
    when "fish" then cook bake
    when "steak" then cook grill
    when "french fries" then cook fry
    when "apple"
        if appleSeason is true
            cook none
        else
            cook bake
    when "water" then cook boil
    else cook pan

With CoffeeScript, curly braces and parentheses are not used.

Parentheses are not required for if conditions:

if day="Saturday"
  sleep_late
else
  groan()

CoffeeScript also allows the statement to be written in a way that corresponds more with the way we speak. In this example, we might say out loud, “the umbrella is open if raining”. CoffeeScript understands this syntax and correctly complies it to JavaScript.

umbrella = "open" if raining

The equivalent JavaScript code:

var umbrella ;
if ( raining ) {
   umbrella = "open" ;
}

Programmers do not have to worry about deciding whether to use a ternary operator. Simply type the normal if statement. If it can use a ternary operator, CoffeeScript will handle that automatically.

umbrella= if raining then "open" else "close"

The equivalent JavaScript code:

var umbrella ;
umbrella = raining ? "open" : "close" ;

CoffeeScript simplifies loops:

play instrument for instrument in [ "piano" , "violin" , "guitar" ]

The equivalent JavaScript code:

var instrument , _i , _len , _ref ;
_ref = [ "piano" , "violin" , "guitar" ];
for ( _i = 0 , _len = _ref . length ; _i < _len ; _i ++ ) {
   instrument = _ref [ _i ];
   play ( instrument );
}

CoffeeScript also makes it very easy to move through a loop while excluding a certain item. What if a person disliked flute music? They could use the following CoffeeScript code.

instruments = [ "piano" , "violin" , "guitar" , "flute" , "drums" ]
play instrument for instrument in instruments when instrument isnt flute

The equivalent JavaScript code:

var instrument , instruments , _i , _len ;
instruments = [ "piano" , "violin" , "guitar" , "flute" , "drums" ];
for ( _i = 0 , _len = instruments . length ; _i < _len ; _i ++ ) {
   instrument = instruments [ _i ];
   if ( instrument !== flute ) {
     play ( instrument );
   }
}

Because of the way arrays begin with zero, it can sometimes be burdensome to try to keep a numbered list of items. CoffeeScript can also take care of this almost automatically.

instruments = [ "piano" , "violin" , "guitar" , "flute" , "drums" ]
instrument_list count + 1 , instrument for instrument , count in instruments

The equivalent JavaScript code:

var count , instrument , instruments , _i , _len ;
instruments = [ "piano" , "violin" , "guitar" , "flute" , "drums" ];
for ( count = _i = 0 , _len = instruments . length ; _i < _len ; count = ++ _i ) {
   instrument = instruments [ count ];
   instrument_list ( count + 1 , instrument );
}

CoffeeScript help deal with the switch evil. The switch statement is another very useful component of JavaScript. It allows for comparisons to be made more efficiently when there are multiple condition options. However, the switch statement is not without its problems. Many programmers have spent hours trying to find a mistake that eventually was discovered as the omission of break within one of the switch conditions. Leaving out a break causes the program to continue to run through to the next option. Using CoffeeScript to create switch statements eliminates much of the headache. Notice the vast difference in the amount of code required for CoffeeScript vs. JavaScript. The CoffeeScript is also more easily read by humans. This reduces the number of potential coding errors.

switch food
   when "fish" then cook bake
   when "steak" then cook grill
   when "french fries" then cook fry
   when "sashimi" then cook none
   when "apple"
     if appleSeason is true
       cook none
     else
       cook bake
   when "water" then cook boil
   else cook pan

The equivalent JavaScript code:

switch ( food ) {
   case "fish" :
     cook ( bake );
     break ;

   case "steak" :
     cook ( grill );
     break ;

   case "french fries" :
     cook ( fry );
     break ;

   case "sashimi" :
     cook ( none );
     break ;

   case "apple"
     if ( appleSeason === true )
       cook ( none );
     } else {
       cook ( bake );
     }

     break ;

   case "water" :
     cook ( boil );
     break ;
   default :
     cook ( pan );
}

CoffeeScript also allows for very easy comparison to a range of values. If you have a database of users, it might be useful to know which ones are teenagers. This would mean you are looking for users who are more than 12 years old but less than 20. With CoffeeScript, this can be done on one line of code.

teenager = 12 > age < 20

JavaScript code:

var teenager ;
teenager = ( 12 > age && age < 20 );

CoffeeScript:

class A 
  a: ()->
    console.log(@)
    b=()-> console.log(@)
    b()

a = new A
a.a()

JavaScript:

var A, a;

A = (function() {
  function A() {}

  A.prototype.a = function() {
    var b;
    console.log(this);
    b = function() {
      return console.log(this);
    };
    return b();
  };

  return A;

})();

a = new A;

a.a();

How can we write a simple function using CoffeeScript?

calculateTotalPrice = (arg1,arg2) ->
   subtotal = arg1 + arg2
   tax = subtotal * 0.085
   subtotal + tax

What are some CoffeeScript's pit-falls?

numberOfRadios = index -1

is not the same as:

numberOfRadios = index - 1

Did you notice that there’s a space after the minus sign in the second example? The reason for this behavior is that the first line will be converted by the compiler to the function invocation and that is probably not what you wanted.

var numberOfRadios;
numberOfRadios = index(-1);

Another pitfall, that leads to writing despondently inconsistent code (by us developers), is caused by the fact that parentheses are optional for function calls.

This example involves if conditions in which we want to compare the value of the expression model.get() or the operand typeof to some strings:

a() if @model.get 'groupType' is 'radioGroupTabs'
a() if typeof @model.get 'condition' is 'function'

CoffeeScript is treating the entire thing as an argument and the results are pathetic. Duh. ;-( Here is the native JavaScript code:

if (this.model.get('groupType' === 'radioGroupTabs')) {
  a();
}

if (typeof this.model.get('condition' === 'function')) {
  a();
}

Placing parens over the function still does us no good. Look at this CoffeeScript code:

a() if @model.get ('groupType') is 'radioGroupTabs'

And its JavaScript output:

if (this.model.get('groupType' === 'radioGroupTabs')) {
  a();
}

The workaround involves using () around function calls, or flipping the order in the if statement so that the function invocation is the last bit of code in the if statement:

a() if (typeof @model.get 'condition') is 'function'
a() if 'function' is typeof @model.get 'condition'
a() if (@model.get 'groupType') is 'radioGroupTabs'
a() if 'radioGroupTabs' is  @model.get ('groupType')

The code above compiles to what we wanted originally:

if ((typeof this.model.get('condition')) === 'function') {
  a();
}

if ('function' === typeof this.model.get('condition')) {
  a();
}

if ((this.model.get('groupType')) === 'radioGroupTabs') {
  a();
}

if ('radioGroupTabs' === this.model.get('groupType')) {
  a();

Is it all good now? Not really, because I personally think this approach leads to inconsistencies: parts of CoffeeScript code that must have parentheses, while in other places they are optional.

The next note explains the most common beginner’s mistake in CoffeeScript; that is to use an a instead of an a() for function calls. However, super inside of a class, must be called without parentheses in order to pass the arguments to it.

Moving on to the single hash (#) comments which are just skipped over by CoffeeScript. Again, this can lead to unexpected consequences. For example, a straightforward if statement has a few lines of code:

unless A 
  b()
  blah blah

But if we comment out all of the lines inside of if, the whole thing will fail miserably at the compilation step

unless A 
  # b()
  # blah blah

Just by adding an empty else we can mitigate the failure:

unless A 
  # b()
  # blah blah
else

c() # the code continues here

Last but not least, there is another CoffeeScript pitfall related to jQuery events that don’t propagate when the event handler returns false. Of course, CoffeeScript philosophy makes every function an expression (the last statement is evaluated if there is no return statement present).

b = ()->
  false # usually this result is less obvious and buried deep down in code
$a = $ 'input'
$a.click ()->
  console.log 'this happens all right'
  b()

$a.parent().click ()->
  console.log('this never happened')

Of course, in real life the b() function is not so obvious and it’s buried somewhere deep within Backbone and Angular model methods. And the event isn’t propagating up the DOM tree (return false). Therefore, we’ve lost the second event handler without even realizing it.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License