CoffeeScript
Programming language which compiles to JavaScript
- 9 min read
- 6 chapters
Related on Lably
Through JavaScript, Python (programming language) and Assignment (computer science)
CoffeeScript support is included in Ruby on Rails version 3.1 and Play Framework. In 2011, Brendan Eich referenced CoffeeScript as an influence on his thoughts about the future of JavaScript.
History
On December 13, 2009, Jeremy Ashkenas made the first Git commit of CoffeeScript with the comment "initial commit of the mystery language". The compiler was written in Ruby. On December 24, he made the first tagged and documented release, 0.1.0. On February 21, 2010, he committed version 0.5, which replaced the Ruby compiler with a self-hosting version in pure CoffeeScript. By that time the project had attracted several other contributors on GitHub, and was receiving over 300 page hits per day.
On December 24, 2010, Ashkenas announced the release of stable 1.0.0 to Hacker News, the site where the project was announced for the first time.
On September 18, 2017, version 2.0.0 was introduced, which "aims to bring CoffeeScript into the modern JavaScript era, closing gaps in compatibility with JavaScript while preserving the clean syntax that is CoffeeScript's hallmark".
Sign in to keep reading
5 more chapters are free with a Lably account.
Syntax
Almost everything is an expression in CoffeeScript, for example, if, switch and for expressions (which have no return value in JavaScript) return a value. As in Perl and Ruby, these control statements also have postfix versions; for example, if can also be written in consequent if condition form.
Many unnecessary parentheses and braces can be omitted; for example, blocks of code can be denoted by indentation instead of braces, function calls are implicit, and object literals are often detected automatically.
To compute the body mass index in JavaScript, one could write:
<span id="mwYA"></span><span class="kd" id="mwYQ">let</span><span class="w" id="mwYg"> </span><span class="nx" id="mwYw">mass</span><span class="w" id="mwZA"> </span><span class="o" id="mwZQ">=</span><span class="w" id="mwZg"> </span><span class="mf" id="mwZw">72</span><span class="p" id="mwaA">;</span> <span class="kd" id="mwaQ">let</span><span class="w" id="mwag"> </span><span class="nx" id="mwaw">height</span><span class="w" id="mwbA"> </span><span class="o" id="mwbQ">=</span><span class="w" id="mwbg"> </span><span class="mf" id="mwbw">1.78</span><span class="p" id="mwcA">;</span> <span class="kd" id="mwcQ">let</span><span class="w" id="mwcg"> </span><span class="nx" id="mwcw">BMI</span><span class="w" id="mwdA"> </span><span class="o" id="mwdQ">=</span><span class="w" id="mwdg"> </span><span class="nx" id="mwdw">mass</span><span class="w" id="mweA"> </span><span class="o" id="mweQ">/</span><span class="w" id="mweg"> </span><span class="nx" id="mwew">height</span><span class="o" id="mwfA">**</span><span class="mf" id="mwfQ">2</span><span class="p" id="mwfg">;</span> <span class="k" id="mwfw">if</span><span class="w" id="mwgA"> </span><span class="p" id="mwgQ">(</span><span class="mf" id="mwgg">18.5</span><span class="w" id="mwgw"> </span><span class="o" id="mwhA"><=</span><span class="w" id="mwhQ"> </span><span class="nx" id="mwhg">BMI</span><span class="w" id="mwhw"> </span><span class="o" id="mwiA">&&</span><span class="w" id="mwiQ"> </span><span class="nx" id="mwig">BMI</span><span class="w" id="mwiw"> </span><span class="o" id="mwjA"><</span><span class="w" id="mwjQ"> </span><span class="mf" id="mwjg">25</span><span class="p" id="mwjw">)</span><span class="w" id="mwkA"> </span><span class="nx" id="mwkQ">alert</span><span class="p" id="mwkg">(</span><span class="s1" id="mwkw">'You are healthy!'</span><span class="p" id="mwlA">);</span>
With CoffeeScript the interval is directly described:
<span id="mwmA"></span><span class="nv" id="mwmQ">mass</span><span class="w" id="mwmg"> </span><span class="o" id="mwmw">=</span><span class="w" id="mwnA"> </span><span class="mi" id="mwnQ">72</span> <span class="nv" id="mwng">height</span><span class="w" id="mwnw"> </span><span class="o" id="mwoA">=</span><span class="w" id="mwoQ"> </span><span class="mf" id="mwog">1.78</span> <span class="nv" id="mwow">BMI</span><span class="w" id="mwpA"> </span><span class="o" id="mwpQ">=</span><span class="w" id="mwpg"> </span><span class="nx" id="mwpw">mass</span><span class="w" id="mwqA"> </span><span class="o" id="mwqQ">/</span><span class="w" id="mwqg"> </span><span class="nx" id="mwqw">height</span><span class="o" id="mwrA">**</span><span class="mi" id="mwrQ">2</span> <span class="nx" id="mwrg">alert</span><span class="w" id="mwrw"> </span><span class="s" id="mwsA">'You are healthy!'</span><span class="w" id="mwsQ"> </span><span class="k" id="mwsg">if</span><span class="w" id="mwsw"> </span><span class="mf" id="mwtA">18.5</span><span class="w" id="mwtQ"> </span><span class="o" id="mwtg"><=</span><span class="w" id="mwtw"> </span><span class="nx" id="mwuA">BMI</span><span class="w" id="mwuQ"> </span><span class="o" id="mwug"><</span><span class="w" id="mwuw"> </span><span class="mi" id="mwvA">25</span>
To compute the greatest common divisor of two integers with the Euclidean algorithm, in JavaScript one usually needs a while loop:
<span id="mwww"></span><span class="kd" id="mwxA">let</span><span class="w" id="mwxQ"> </span><span class="nx" id="mwxg">gcd</span><span class="w" id="mwxw"> </span><span class="o" id="mwyA">=</span><span class="w" id="mwyQ"> </span><span class="p" id="mwyg">(</span><span class="nx" id="mwyw">x</span><span class="p" id="mwzA">,</span><span class="w" id="mwzQ"> </span><span class="nx" id="mwzg">y</span><span class="p" id="mwzw">)</span><span class="w" id="mw0A"> </span><span class="p" id="mw0Q">=></span><span class="w" id="mw0g"> </span><span class="p" id="mw0w">{</span> <span class="w" id="mw1A"> </span><span class="k" id="mw1Q">do</span><span class="w" id="mw1g"> </span><span class="p" id="mw1w">{</span> <span class="w" id="mw2A"> </span><span class="p" id="mw2Q">[</span><span class="nx" id="mw2g">x</span><span class="p" id="mw2w">,</span><span class="w" id="mw3A"> </span><span class="nx" id="mw3Q">y</span><span class="p" id="mw3g">]</span><span class="w" id="mw3w"> </span><span class="o" id="mw4A">=</span><span class="w" id="mw4Q"> </span><span class="p" id="mw4g">[</span><span class="nx" id="mw4w">y</span><span class="p" id="mw5A">,</span><span class="w" id="mw5Q"> </span><span class="nx" id="mw5g">x</span><span class="o" id="mw5w">%</span><span class="nx" id="mw6A">y</span><span class="p" id="mw6Q">];</span> <span class="w" id="mw6g"> </span><span class="p" id="mw6w">}</span><span class="w" id="mw7A"> </span><span class="k" id="mw7Q">while</span><span class="w" id="mw7g"> </span><span class="p" id="mw7w">(</span><span class="nx" id="mw8A">y</span><span class="w" id="mw8Q"> </span><span class="o" id="mw8g">!==</span><span class="w" id="mw8w"> </span><span class="mf" id="mw9A">0</span><span class="p" id="mw9Q">)</span> <span class="w" id="mw9g"> </span><span class="k" id="mw9w">return</span><span class="w" id="mw-A"> </span><span class="nx" id="mw-Q">x</span><span class="p" id="mw-g">;</span> <span class="p" id="mw-w">}</span>Whereas in CoffeeScript one can use until instead:
<span id="mwAQQ"></span><span class="nv" id="mwAQU">gcd</span><span class="w" id="mwAQY"> </span><span class="o" id="mwAQc">=</span><span class="w" id="mwAQg"> </span><span class="nf" id="mwAQk">(x, y) -></span> <span class="w" id="mwAQo"> </span><span class="p" id="mwAQs">[</span><span class="nx" id="mwAQw">x</span><span class="p" id="mwAQ0">,</span><span class="w" id="mwAQ4"> </span><span class="nx" id="mwAQ8">y</span><span class="p" id="mwARA">]</span><span class="w" id="mwARE"> </span><span class="o" id="mwARI">=</span><span class="w" id="mwARM"> </span><span class="p" id="mwARQ">[</span><span class="nx" id="mwARU">y</span><span class="p" id="mwARY">,</span><span class="w" id="mwARc"> </span><span class="nx" id="mwARg">x</span><span class="o" id="mwARk">%</span><span class="nx" id="mwARo">y</span><span class="p" id="mwARs">]</span><span class="w" id="mwARw"> </span><span class="k" id="mwAR0">until</span><span class="w" id="mwAR4"> </span><span class="nx" id="mwAR8">y</span><span class="w" id="mwASA"> </span><span class="o" id="mwASE">is</span><span class="w" id="mwASI"> </span><span class="mi" id="mwASM">0</span> <span class="w" id="mwASQ"> </span><span class="nx" id="mwASU">x</span>
The ? keyword quickly checks if a variable is null or undefined :
<span id="mwAS0"></span><span class="nv" id="mwAS4">personCheck</span><span class="w" id="mwAS8"> </span><span class="o" id="mwATA">=</span><span class="w" id="mwATE"> </span><span class="nf" id="mwATI">-></span> <span class="w" id="mwATM"> </span><span class="k" id="mwATQ">if</span><span class="w" id="mwATU"> </span><span class="o" id="mwATY">not</span><span class="w" id="mwATc"> </span><span class="nx" id="mwATg">person</span><span class="o" id="mwATk">?</span><span class="w" id="mwATo"> </span><span class="k" id="mwATs">then</span><span class="w" id="mwATw"> </span><span class="nx" id="mwAT0">alert</span><span class="p" id="mwAT4">(</span><span class="s" id="mwAT8">"No person"</span><span class="p" id="mwAUA">)</span><span class="w" id="mwAUE"> </span><span class="k" id="mwAUI">else</span><span class="w" id="mwAUM"> </span><span class="nx" id="mwAUQ">alert</span><span class="p" id="mwAUU">(</span><span class="s" id="mwAUY">"Have person"</span><span class="p" id="mwAUc">)</span> <span class="nv" id="mwAUg">person</span><span class="w" id="mwAUk"> </span><span class="o" id="mwAUo">=</span><span class="w" id="mwAUs"> </span><span class="kc" id="mwAUw">null</span> <span class="nx" id="mwAU0">personCheck</span><span class="p" id="mwAU4">()</span> <span class="nv" id="mwAU8">person</span><span class="w" id="mwAVA"> </span><span class="o" id="mwAVE">=</span><span class="w" id="mwAVI"> </span><span class="s" id="mwAVM">"Ivan"</span> <span class="nx" id="mwAVQ">personCheck</span><span class="p" id="mwAVU">()</span>
This would alert "No person" if the variable is null or undefined and "Have person" if there is something there.
A common pre-ES6 JavaScript snippet using the jQuery library is:
<span id="mwAV4"></span><span class="nx" id="mwAV8">$</span><span class="p" id="mwAWA">(</span><span class="nb" id="mwAWE">document</span><span class="p" id="mwAWI">).</span><span class="nx" id="mwAWM">ready</span><span class="p" id="mwAWQ">(</span><span class="kd" id="mwAWU">function</span><span class="p" id="mwAWY">()</span><span class="w" id="mwAWc"> </span><span class="p" id="mwAWg">{</span> <span class="w" id="mwAWk"> </span><span class="c1" id="mwAWo">// Initialization code goes here</span> <span class="p" id="mwAWs">});</span>Or even just:
<span id="mwAW8"></span><span class="nx" id="mwAXA">$</span><span class="p" id="mwAXE">(</span><span class="kd" id="mwAXI">function</span><span class="p" id="mwAXM">()</span><span class="w" id="mwAXQ"> </span><span class="p" id="mwAXU">{</span> <span class="w" id="mwAXY"> </span><span class="c1" id="mwAXc">// Initialization code goes here</span> <span class="p" id="mwAXg">});</span>In CoffeeScript, the function keyword is replaced by the -> symbol, and indentation is used instead of curly braces, as in other off-side rule languages such as Python and Haskell. Also, parentheses can usually be omitted, using indentation level instead to denote a function or block. Thus, the CoffeeScript equivalent of the snippet above is:
<span id="mwAX8"></span><span class="nx" id="mwAYA">$</span><span class="p" id="mwAYE">(</span><span class="nb" id="mwAYI">document</span><span class="p" id="mwAYM">).</span><span class="nx" id="mwAYQ">ready</span><span class="w" id="mwAYU"> </span><span class="nf" id="mwAYY">-></span> <span class="w" id="mwAYc"> </span><span class="c1" id="mwAYg"># Initialization code goes here</span>
Or just:
<span id="mwAYw"></span><span class="nx" id="mwAY0">$</span><span class="w" id="mwAY4"> </span><span class="nf" id="mwAY8">-></span> <span class="w" id="mwAZA"> </span><span class="c1" id="mwAZE"># Initialization code goes here</span>
Ruby-style string interpolation is included in CoffeeScript. Double-quoted strings allow for interpolated values, using #{ ... }, and single-quoted strings are literal.
<span id="mwAZk"></span><span class="nv" id="mwAZo">author</span><span class="w" id="mwAZs"> </span><span class="o" id="mwAZw">=</span><span class="w" id="mwAZ0"> </span><span class="s" id="mwAZ4">"Wittgenstein"</span> <span class="nv" id="mwAZ8">quote</span><span class="w" id="mwAaA"> </span><span class="o" id="mwAaE">=</span><span class="w" id="mwAaI"> </span><span class="s" id="mwAaM">"A picture is a fact. -- </span><span class="si" id="mwAaQ">#{</span><span class="w" id="mwAaU"> </span><span class="nx" id="mwAaY">author</span><span class="w" id="mwAac"> </span><span class="si" id="mwAag">}</span><span class="s" id="mwAak">"</span> <span class="nv" id="mwAao">sentence</span><span class="w" id="mwAas"> </span><span class="o" id="mwAaw">=</span><span class="w" id="mwAa0"> </span><span class="s" id="mwAa4">"</span><span class="si" id="mwAa8">#{</span><span class="w" id="mwAbA"> </span><span class="mi" id="mwAbE">22</span><span class="w" id="mwAbI"> </span><span class="o" id="mwAbM">/</span><span class="w" id="mwAbQ"> </span><span class="mi" id="mwAbU">7</span><span class="w" id="mwAbY"> </span><span class="si" id="mwAbc">}</span><span class="s" id="mwAbg"> is a decent approximation of π"</span>Any for loop can be replaced by a list comprehension; so that to compute the squares of the positive odd numbers smaller than ten (i.e. numbers whose remainder modulo 2 is 1), one can do:
<span id="mwAb8"></span><span class="nx" id="mwAcA">alert</span><span class="w" id="mwAcE"> </span><span class="nx" id="mwAcI">n</span><span class="o" id="mwAcM">*</span><span class="nx" id="mwAcQ">n</span><span class="w" id="mwAcU"> </span><span class="k" id="mwAcY">for</span><span class="w" id="mwAcc"> </span><span class="nx" id="mwAcg">n</span><span class="w" id="mwAck"> </span><span class="k" id="mwAco">in</span><span class="w" id="mwAcs"> </span><span class="p" id="mwAcw">[</span><span class="mi" id="mwAc0">1</span><span class="p" id="mwAc4">..</span><span class="mi" id="mwAc8">10</span><span class="p" id="mwAdA">]</span><span class="w" id="mwAdE"> </span><span class="k" id="mwAdI">when</span><span class="w" id="mwAdM"> </span><span class="nx" id="mwAdQ">n</span><span class="o" id="mwAdU">%</span><span class="mi" id="mwAdY">2</span><span class="w" id="mwAdc"> </span><span class="o" id="mwAdg">is</span><span class="w" id="mwAdk"> </span><span class="mi" id="mwAdo">1</span>
Alternatively, there is:
<span id="mwAd4"></span><span class="nx" id="mwAd8">alert</span><span class="w" id="mwAeA"> </span><span class="nx" id="mwAeE">n</span><span class="o" id="mwAeI">*</span><span class="nx" id="mwAeM">n</span><span class="w" id="mwAeQ"> </span><span class="k" id="mwAeU">for</span><span class="w" id="mwAeY"> </span><span class="nx" id="mwAec">n</span><span class="w" id="mwAeg"> </span><span class="k" id="mwAek">in</span><span class="w" id="mwAeo"> </span><span class="p" id="mwAes">[</span><span class="mi" id="mwAew">1</span><span class="p" id="mwAe0">..</span><span class="mi" id="mwAe4">10</span><span class="p" id="mwAe8">]</span><span class="w" id="mwAfA"> </span><span class="k" id="mwAfE">by</span><span class="w" id="mwAfI"> </span><span class="mi" id="mwAfM">2</span>
A linear search can be implemented with a one-liner using the when keyword:
<span id="mwAfg"></span><span class="nv" id="mwAfk">names</span><span class="w" id="mwAfo"> </span><span class="o" id="mwAfs">=</span><span class="w" id="mwAfw"> </span><span class="p" id="mwAf0">[</span><span class="s" id="mwAf4">"Ivan"</span><span class="p" id="mwAf8">,</span><span class="w" id="mwAgA"> </span><span class="s" id="mwAgE">"Joanna"</span><span class="p" id="mwAgI">,</span><span class="w" id="mwAgM"> </span><span class="s" id="mwAgQ">"Nikolay"</span><span class="p" id="mwAgU">,</span><span class="w" id="mwAgY"> </span><span class="s" id="mwAgc">"Mihaela"</span><span class="p" id="mwAgg">]</span> <span class="nv" id="mwAgk">linearSearch</span><span class="w" id="mwAgo"> </span><span class="o" id="mwAgs">=</span><span class="w" id="mwAgw"> </span><span class="nf" id="mwAg0">(searchName) -></span><span class="w" id="mwAg4"> </span><span class="nx" id="mwAg8">alert</span><span class="p" id="mwAhA">(</span><span class="nx" id="mwAhE">name</span><span class="p" id="mwAhI">)</span><span class="w" id="mwAhM"> </span><span class="k" id="mwAhQ">for</span><span class="w" id="mwAhU"> </span><span class="nx" id="mwAhY">name</span><span class="w" id="mwAhc"> </span><span class="k" id="mwAhg">in</span><span class="w" id="mwAhk"> </span><span class="nx" id="mwAho">names</span><span class="w" id="mwAhs"> </span><span class="k" id="mwAhw">when</span><span class="w" id="mwAh0"> </span><span class="nx" id="mwAh4">name</span><span class="w" id="mwAh8"> </span><span class="o" id="mwAiA">is</span><span class="w" id="mwAiE"> </span><span class="nx" id="mwAiI">searchName</span>
The for ... in syntax allows looping over arrays while the for ... of syntax allows looping over objects.
CoffeeScript has been criticized for its unusual scoping rules. In particular, it completely disallows variable shadowing which makes reasoning about code more difficult and error-prone in some basic programming patterns established by and taken for granted since procedural programming principles were defined.
For example, with the following code snippet in JavaScript one does not have to look outside the {}-block to know for sure that no possible foo variable in the outer scope can be incidentally overridden:
<span id="mwAjc"></span><span class="w" id="mwAjg"> </span><span class="c1" id="mwAjk">// ...</span> <span class="w" id="mwAjo"> </span><span class="kd" id="mwAjs">function</span><span class="w" id="mwAjw"> </span><span class="nx" id="mwAj0">baz</span><span class="p" id="mwAj4">()</span><span class="w" id="mwAj8"> </span><span class="p" id="mwAkA">{</span> <span class="w" id="mwAkE"> </span><span class="kd" id="mwAkI">var</span><span class="w" id="mwAkM"> </span><span class="nx" id="mwAkQ">foo</span><span class="w" id="mwAkU"> </span><span class="o" id="mwAkY">=</span><span class="w" id="mwAkc"> </span><span class="s2" id="mwAkg">"bar"</span><span class="p" id="mwAkk">;</span> <span class="w" id="mwAko"> </span><span class="nx" id="mwAks">console</span><span class="p" id="mwAkw">.</span><span class="nx" id="mwAk0">log</span><span class="p" id="mwAk4">(</span><span class="sb" id="mwAk8">`foo = </span><span class="si" id="mwAlA">${</span><span class="nx" id="mwAlE">foo</span><span class="si" id="mwAlI">}</span><span class="sb" id="mwAlM">`</span><span class="p" id="mwAlQ">);</span> <span class="w" id="mwAlU"> </span><span class="p" id="mwAlY">}</span> <span class="w" id="mwAlc"> </span><span class="c1" id="mwAlg">// ...</span> <span class="p" id="mwAlk">}</span>In CoffeeScript there is no way to tell if the scope of a variable is limited to a block or not without looking outside the block.
Development and distribution
The CoffeeScript compiler has been self-hosting since version 0.5 and is available as a Node.js utility; however, the core compiler does not rely on Node.js and can be run in any JavaScript environment. One alternative to the Node.js utility is the Coffee Maven Plugin, a plugin for the Apache Maven build system. The plugin uses the Rhino JavaScript engine written in Java.
The official site at CoffeeScript.org has a "Try CoffeeScript" button in the menu bar; clicking it opens a modal window in which users can enter CoffeeScript, see the JavaScript output, and run it directly in the browser. The js2coffee site provides bi-directional translation.
Latest additions
- Source maps allow users to debug their CoffeeScript code directly, supporting CoffeeScript tracebacks on run time errors.
- CoffeeScript supports a form of literate programming, using the
.coffee.mdor.litcoffeefile extension. This allows the source code to be written in Markdown. The compiler will treat any indented blocks (Markdown's way of indicating source code) as code, and ignore the rest as comments.
Extensions
Iced CoffeeScript is a superset of CoffeeScript which adds two new keywords: await and defer. These additions simplify asynchronous control flow, making the code look more like a procedural programming language, eliminating the call-back chain. It can be used on the server side and in the browser.
Adoption
On September 13, 2012, Dropbox announced that its browser-side code base had been rewritten from JavaScript to CoffeeScript. However, it was migrated to TypeScript in 2017.
GitHub's internal style guide once said "write new JS in CoffeeScript", though it no longer does, and its Atom text editor was also written in the language, with configuration written in CSON ("CoffeeScript Object Notation"), a variant of JSON.
Pixel Game Maker MV makes uses of CoffeeScript as part of its game development environment.

