In my previous post about CoffeeScript in ASP .NET, I basically concluded that I was ambivalent toward whether or not it’s actually useful in the ASP .NET world. I focused on the fact that CS allows you to type less code and get [mostly] the same results.
In actuality, CoffeeScript does a lot for you behind the scenes to make sure you’re a good JavaScript developer. Josh Harrison pointed this out to me a few weeks ago, and since then I’ve formed a…more educated opinion.
If you’ve ever looked at JavaScript best practices, there’s a lot of them, and there are a lot of nuances you must understand about the language in order to really make sure your code is clean, safe, and just plain rainbows-and-sunshine good. This includes not only a good understanding of variable scoping, value comparisons, type checking, etc., but also where all the pitfalls with those things are.
Well, if you’re using CoffeeScript, it takes care of a lot of those things for you. Try CoffeeScript, write some quick bits of code in CoffeeScript, and see what it does.
What is CoffeeScript?
I won’t spend too much time on this. CoffeeScript is a language which converts to JavaScript when compiled. Its syntax is more concise and Ruby-like, and I think that’s pretty cool. But the compiler adds the value I will talk about in this post.
Variable Scope
The first thing I want to point out is that when you’re writing plain old JavaScript, the variables you declare are public and global by default. This means that if you have the following code:
var foo = 'bar';
Anyone can access this variable outside of the context of your JavaScript file, because foo is scoped globally:
alert(window.foo); // alerts 'bar'
Sometimes you want this, but most of the time, it’s a good idea to keep your variables within your own closure. Closures allow you to control access variables, and remove the possibility that some other JavaScript file might use the same variable on accident. Good news, though, CoffeeScript does this for you! Check it out:
foo = 'bar'
The above CoffeeScript code compiles to this bit of JavaScript:
(function() {
var foo;
foo = 'bar';
}).call(this);
That right there is whatcha call a good ole self-executing enclosure! (if you don’t know what that is, you should.)
No More Var!
You may have noticed that there is not a var keyword in the CoffeeScript snippet above. Isn’t that brilliant?! I think so. CoffeeScript is just smart enough to figure out what variable you are using. Let’s run through a basic scenario.
(function() {
var foo = 'bar';
var fn2 = function() {
var foo = 'baz';
alert(foo);
};
fn2();
alert(foo);
})();
This JS will first alert the value ‘baz’, then it will alert the value ‘bar’. This is because the first var foo is scoped to the outermost closure. The next var foo statement actually creates a new variable which is scoped specifically to the fn2 function, therefore using the foo variable within that function does not affect the outer closure’s foo variable at all. CoffeeScript doesn’t really let this happen. Here’s what the CS would look like if we tried to do this:
foo = 'bar'
fn2 = ->
foo = 'baz'
alert foo
fn2()
alert foo
And this compiles to the following JS:
(function() {
var fn2, foo;
foo = 'bar';
fn2 = function() {
foo = 'baz';
return alert(foo);
};
fn2();
alert(foo);
}).call(this);
The key thing to notice here is that there is only one declaration of the variable foo, and it is in the outermost closure. This means that the fn2 function will reference that variable, rather than its own foo variable. So this script will alert ‘baz’ twice.
Strict Comparisons
One of the nuances of JavaScript is the difference between == and ===. Examples of these differences are all over the ‘net, but to sum it up, == will try to coerce variables to be of the same type to perform comparison, while === will not. So, alert(1 == '1'); will alert ‘true’, but alert(1 === '1'); will alert ‘false’. The safest way to do comparison is to always use the === operator (or !==). In CoffeeScript, you use is and isnt to do comparisons. Here’s some CS:
foo = '1'
bar = 1
alert foo is bar
alert foo isnt bar
alert foo == bar
This compiles to the following JS:
(function() {
var bar, foo;
foo = '1';
bar = 1;
alert(foo === bar);
alert(foo !== bar);
alert(foo === bar);
}).call(this);
Whoa, CoffeeScript even takes my == and turns it into a === operator! Pretty cool. I like to use the more readable is and isnt operators though.
Now, if you’re not used to using === and !==, then you’ll have a little bit of frustration as you are used to just letting JavaScript figure this stuff out for you. But let me tell you, it is much better to get into the habit of using === and !== because it will save you much pain in the long run. To quote Jeremy Ashkenas here,
If you want to compare numbers as strings, convert them to strings … and if you want to compare strings as numbers, parse them as numbers.
JSLint Compliance
If you’re like me, whenever you write JavaScript files, before you finally let them go into production, you run your script through JSLint. CoffeeScript automatically compiles into JSLint-compliant JavaScript, which is wonderful. You can know that the generated JavaScript complies into JavaScript which is clean, and adheres to best practices.
ASP .NET Application
Since I’ve shown some pretty strong business cases for using CoffeeScript to write and compile JavaScript, I suppose I should tell you how to use CoffeeScript from within Visual Studio. I can tell you that I would want to have built-in support for CoffeeScript in Visual Studio, including syntax highlighting, and I would want it to compile to JavaScript and minify it automatically, without a lot of manual steps on my part. Scott Hanselman has an excellent post about Sass and CoffeeScript, and he links to the (free) Mindscape Web Workbench, which adds CoffeeScript (and Sass) support to Visual Studio. It gives you syntax highlighting Pretty awesome. The only sucky thing about is that the free version does not minify your JavaScript (or CSS files) automatically. I understand they’re trying to make money off of this product, but come on, we’re developers – we’re going to find a way around this. Either way, it’s a pretty cool addition to Visual Studio.