Tuesday, January 29, 2013

Oh yeah, Coffeescript

Oh yeah,

One thing I forgot to mention picking up over the last year was Coffeescript.

When I first heard about Coffeescript I was interested.  After checking it out initally I came away rather unimpressed.  It added a more traditional looking class structure for OOP, had some structural changes to loops and conditions but in the end since it compiled down to Javascript and you would be debugging that code, I didn't see the point.

Some time later I decided to give it a shot on a new project and once I started using Coffeescript, I was sold.  I now use Coffeescript on pretty much all projects.  Why?  Once I began to do some real development in Coffeescript I noticed that I was able to work much faster in it than Javascript alone.  The class structure I dismissed early on does come with some features that make it easier in many cases to develop faster.  Simple inheritance with extends and the fat arrow for context binding allows you to code faster without having to dedicate as much time to boilerplate code.

Classes

Javascript doesn't have classes.  It uses a prototypical system for inheritance and everythis is declared using functions.


function A()


}

var a = new A(); 
console.log(a instanceof A); // true

The above code says that instance a has the constructor of A in it's prototype chain and will contain it's properties and methods.

Too add properties and methods we

A.prototype.info = "On the prototype";

A.prototype.hotMethod = function(){ 
 return "this method is hot"; 
};

console.log(a.info); // On the prototype
console.log(a.hotMethod()); // this method is hot

When we get to inheritance that's where it get's hairy for many people, myself included

function B(){

}

B.prototype = new A(); 

B.prototype.newHotMethod = function(){ 
 return "this method is the new hotness" 
};

var b = new B(); 
console.log(b instanceof B); // true
console.log(b.hotMethod()); // this method is hot
console.log(b.newHotMethod()); // this method is the new hotness

There are better more thorough ways of doing inheritance in javascript but that will work.

Here is the same basic class setup in Coffeescript

class A 

 constructor: () -> 
 info: "this is on A" 
 hotMethod: () -> "this method is hot" 

a = new A();
console.log(a instanceof A) // true 
console.log(a.info) // this is on A 
console.log(a.hotMethod()) // this method is hot

And basic inheritance

class B extends A 
 constructor: () -> 
 newHotMethod: () -> "this method is the new hotness" 
 b = new B();

console.log(b instanceof B) // true
console.log(b.info) // this is on A 
console.log(b.hotMethod()) //this method is hot 
console.log(b.newHotMethod()) //this method is the new hotness

As you can see the Coffeescript is slightly less verbose and more easily readable, which can make it both faster to code and easier to maintain.

The Fat Arrow

Not simply a gluttonous arrow, fat arrow notation has actually worked it's way into a future version of Javascript.  Using this keyword is javascript can lead to some gotchas, such as the following:

function App(){ 
 this.something = "something!"

 var theClick = function(evt){ 
   console.log(this); // the button that emited the event
   console.log(this.something); //undefined 
 }; 

 this.notTheClick = function(){ 
   console.log(this.something); // something! 
 }; 

 $("#clickit").on("click", theClick); 
 this.notTheClick(); //something


run = new App();

That is a totally contrived, non-sense example of scope issues in javascript (featuring jQuery) but it does prove the point. The context for the event handler is different from the enclosing App function but on visual inspection that is difficult to tell. In Coffeescript we have the fat and skinny arrows for context resolution

class App constructor: () -> 
   $("#clickit").on("click", @fatArrowHotness) 
 fatArrowHotness: () => ##binds it to the instance of App
   console.log(@) // context is App instance 

 runApp = new App()

One thing you'll notice here is my use of the @ symbol which is an alias for this in Coffeescript. As promised, using the fat arrow has bound the context of fatArrowHotness to the instance of App, if you use a skinny arrow the context would be the DOM element that emitted the click event.

class App 
 constructor: () -> 
   $("#clickit").on("click", @thinArrowHotness) 
 thinArrowHotness: () -> 
   console.log(@) // the DOM element that was clicked 

 runApp = new App()

The fat arrow makes scope resolution far easier to see at a glance which again can lead to faster development and easier maintanence.

These are just a couple of reasons I have been using Coffeescript so heavily over the last little bit, I hope to share more of why I enjoy Coffeescript in the next little bit.

No comments:

Post a Comment