diff --git a/documentation/cs/conditionals.cs b/documentation/cs/conditionals.cs index 253d912c..5d1f985e 100644 --- a/documentation/cs/conditionals.cs +++ b/documentation/cs/conditionals.cs @@ -6,4 +6,4 @@ if happy and knows_it date: if friday then sue else jill. -expensive ||= do_the_math() \ No newline at end of file +expensive ||: do_the_math() \ No newline at end of file diff --git a/documentation/cs/overview.cs b/documentation/cs/overview.cs new file mode 100644 index 00000000..8e44f8aa --- /dev/null +++ b/documentation/cs/overview.cs @@ -0,0 +1,22 @@ +# Assignment: +number: 42 +opposite_day: true + +# Conditions: +number: -42 if opposite_day + +# Functions: +square: x => x * x. + +# Arrays: +list: [1, 2, 3, 4, 5] + +# Objects: +math: { + root: Math.sqrt + square: square + cube: x => x * square(x). +} + +# Array comprehensions: +cubed_list: math.cube(num) for num in list. diff --git a/documentation/cs/try.cs b/documentation/cs/try.cs index 6664bbd1..8a2c6275 100644 --- a/documentation/cs/try.cs +++ b/documentation/cs/try.cs @@ -2,6 +2,6 @@ try all_hell_breaks_loose() cats_and_dogs_living_together() catch error - print( error ) + print(error) finally clean_up(). \ No newline at end of file diff --git a/documentation/css/docs.css b/documentation/css/docs.css index 3d11307b..dd2a4f86 100644 --- a/documentation/css/docs.css +++ b/documentation/css/docs.css @@ -30,32 +30,34 @@ b.header { margin: 40px 0 5px 0; font-size: 16px; } -table, tr, td { - margin: 0; padding: 0; +table { + margin: 16px 0 0 13px; padding: 0; + width: 625px; } - td { - padding: 2px 12px 2px 0; + tr, td { + margin: 0; padding: 0; } + td { + padding: 9px 15px 9px 0; + } code, pre, tt { font-family: Monaco, Consolas, "Lucida Console", monospace; font-size: 12px; line-height: 18px; - color: #555529; + color: #191955; } - code { - margin-left: 20px; + tt { + background: #f8f8ff; + border: 1px solid #dedede; + font-size: 85%; + padding: 0px 0.2em; } pre { + border-left: 6px solid #222255; + margin-left: 13px; + padding: 3px 0 3px 12px; font-size: 12px; - padding: 0 0 0 12px; - margin: 0; - width: 410px; - float: left; - border-left: 1px dotted #559; } - pre:first-child { - border-left: 0; - } div.code { position: relative; border: 1px solid #cacaca; @@ -67,4 +69,14 @@ div.code { div.code button { position: absolute; right: 8px; bottom: 8px; - } \ No newline at end of file + } + div.code pre { + float: left; + width: 410px; + border-left: 1px dotted #559; + padding: 0 0 0 12px; + margin: 0; + } + div.code pre:first-child { + border-left: 0; + } \ No newline at end of file diff --git a/documentation/index.html.erb b/documentation/index.html.erb index 8d2086d2..b2ea5486 100644 --- a/documentation/index.html.erb +++ b/documentation/index.html.erb @@ -2,6 +2,7 @@ require 'uv' def code_for(file, executable=false) @stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/ + return '' unless File.exists?("documentation/js/#{file}.js") cs = File.read("documentation/cs/#{file}.cs") js = File.read("documentation/js/#{file}.js").gsub(@stripper, '') cshtml = Uv.parse(cs, 'xhtml', 'coffeescript', false, 'idle', false) @@ -30,10 +31,10 @@
CoffeeScript is a little language that compiles into JavaScript. Think - of it as JavaScript's simpleminded kid brother — the same genes, + of it as JavaScript's less ostentatious kid brother — the same genes, the same accent, but a different sense of style. Apart from a handful of - bonus goodies, statements in CoffeeScript correspond one-to-one with their - JavaScript equivalent, it's just another way of saying it. + bonus goodies, statements in CoffeeScript correspond one-to-one with their + equivalent in JavaScript, it's just another way of saying it.
@@ -41,181 +42,303 @@Disclaimer: CoffeeScript is just for fun and seriously alpha. There is no guarantee, - explicit or implied, of its suitability for any purpose. That said, it - compiles into pretty-printed JavaScript (the good parts) that can pass through - JSLint warning-free. + explicit or implied, of its suitability for any purpose. That said, + it compiles into clean JavaScript (the good parts) that can use existing + JavaScript libraries seamlessly, and can pass through + JSLint without warnings. The compiled + scripts are quite readable — pretty-printed, with comments + preserved intact.
- - This document is structured so that it can be read from top to bottom, - if you like. Later sections use ideas and syntax previously introduced. - -
- -
+ Mini Overview
+ Installation and Usage
Punctuation Primer
Functions and Invocation
- Objects and Arrays
Assignment
+ Objects and Arrays
Lexical Scoping and Variable Safety
Conditionals, Ternaries, and Conditional Assignment
Everything is an Expression
While Loops
Array Comprehensions
Array Slice Literals
- Inheritance, and Calling Super from a Subclass
+ Calling Super from a Subclass
Embedded JavaScript
+ Aliases
Switch/Case/Else
Try/Catch/Finally
Multiline Strings
CoffeeScript on the left, compiled JavaScript output on the right.
+ + <%= code_for('overview', 'cubed_list') %> + ++sudo gem install coffee-script+
- In all of the following examples, the source CoffeeScript is provided on - the left, and the direct compilation into JavaScript is on the right. + Installing the gem provides the coffee-script command, which can + be used to compile CoffeeScript .cs files into JavaScript, as + well as debug. By default, coffee-script writes out the + JavaScript as .js files in the same directory, but output + can be customized with the following options:
--o, --output [DIR] |
+ + Write out all compiled JavaScript files into the specified directory. + | +
-w, --watch |
+ + Watch the modification times of the named scripts, recompiling as + soon as a change occurs. + | +
-p, --print |
+ + Instead of writing out the JavaScript as a file, print it + directly to stdout. + | +
-l, --lint |
+ + If the jsl (JavaScript Lint) command is installed, use it + to check the compilation of a CoffeeScript file. + | +
-e, --eval |
+
+ Compile and print a little snippet of CoffeeScript directly from the
+ command line. For example: coffee-script -e "square: x => x * x." + |
+
-t, --tokens |
+ + Instead of parsing the CoffeeScript, just lex it, and print out the + token stream: [:IDENTIFIER, "square"], [":", ":"], [:PARAM, "x"] ... + | +
-v, --verbose |
+ + As the JavaScript is being generated, print out every step of code + generation, including lexical scope and the node in the + AST. + | +
- Punctuation Primer - You don't need to use semicolons to (;) terminate expressions, ending - the line will do just as well. So newlines can matter, but whitespace is - not otherwise significant. Instead of using curly braces ({ }) - to delimit blocks of code, a period (.) marks the end of a - function, if statement, or try/catch. -
- ++ Examples: +
-- Functions and Invocation - Let's start with the best part, shall we? Function literals are my - absolute favorite thing about CoffeeScript. -
- <%= code_for('functions', 'cube(5)') %> ++coffee-script path/to/script.cs +coffee-script --watch --lint experimental.cs +coffee-script --print app/scripts/*.cs > concatenation.js-
- Objects and Arrays - Object and Array literals look very similar. When you spread out - each assignment on a separate line, the commas are optional. -
- <%= code_for('objects_and_arrays', 'song.join(",")') %> --
+- Assignment - All assignment in CoffeeScript, whether to a variable or to an object - property, uses a colon. Equal signs are only needed for mathy things. -
- <%= code_for('assignment', 'greeting') %> --
++ + This document is structured so that it can be read from top to bottom, + if you like. Later sections use ideas and syntax previously introduced. + In all of the following examples, the source CoffeeScript is provided on + the left, and the direct compilation into JavaScript is on the right. + Familiarity with JavaScript is assumed, although it would certainly + be nice to have a tutorial that builds from the ground up in the future. + +
-- Lexical Scoping and Variable Safety - The CoffeeScript compiler takes care to make sure that all of your variables - are properly defined within lexical scope — you never need to declare - var yourself. -
- <%= code_for('scope', 'new_num') %> -- Notice how the variables are declared with var the first time - they appear. The second reference of num, within the function, - is not redeclared because num is still in scope. As opposed - to the second new_num, in the last line. -
++ Punctuation Primer + You don't need to use semicolons ; to terminate expressions, ending + the line will do just as well. All other whitespace is + not significant. Instead of using curly braces { } + to delimit a block of code, use a period . to mark the end of a + function, if-statement, switch, or try/catch. +
-- Conditionals, Ternaries, and Conditional Assignment -
- <%= code_for('conditionals') %> --
++ Functions and Invocation + Let's start with the best part, shall we? Functions are defined + by a list of parameters, an arrow, and the function body. The empty + function looks like this: =>. +
+ <%= code_for('functions', 'cube(5)') %> -- Everything is an Expression - You might have noticed how even though we don't add return statements - to CoffeScript functions, they nonetheless return their final value. - The CoffeeScript compiler tries to make sure that every little language - construct can be used as an expression. -
- <%= code_for('expressions', 'eldest') %> -- When compiling a function definition, CoffeeScript tries to push down - the return statement to each of the potential final lines of the function. - It uses the same mechanism to push down assignment statements. If statement - are compiled into ternary operators when possible, so that they can be used - as expressions. -
++ Assignment + Use a colon : to assign, as in + JSON. Equal signs are only needed for + mathy things. +
+ <%= code_for('assignment', 'greeting') %> -- While Loops - The only low-level loop that CoffeeScript provides is the while loop. -
- <%= code_for('while') %> ++ Objects and Arrays + Object and Array literals look very similar to their JavaScript cousins. + When you spread out each assignment on a separate line, the commas are + optional. In this way, assigning object properties looks the same as + assigning local variables. +
+ <%= code_for('objects_and_arrays', 'song.join(",")') %> -- Array Comprehensions - Most of your looping needs should be handled by array comprehensions. - They replace (and compile into) for loops, handling - each/forEach style loops, as well as select/filter. - Unlike for loops, array comprehensions are expressions, and can be returned - and assigned. -
- <%= code_for('array_comprehensions') %> ++ Lexical Scoping and Variable Safety + The CoffeeScript compiler takes care to make sure that all of your variables + are properly defined within lexical scope — you never need to declare + var yourself. +
+ <%= code_for('scope', 'new_num') %> ++ Notice how the variables are declared with var the first time + they appear. The second reference of num, within the function, + is not redeclared because num is still in scope. As opposed + to the second new_num, in the last line. +
++ Although suppressed within this documentation, all + CoffeeScript output is wrapped in an anonymous function: + (function(){ ... })(); This safety wrapper, combined with the + automatic generation of the var keyword, make it exceedingly difficult + to pollute the global namespace by accident. +
-- Array Slice Literals - CoffeeScript includes a literal syntax for extracting slices of arrays. - The first argument is the index of the first element in the slice, and - the second is the index of the last one. -
- <%= code_for('slices', 'three_to_six') %> ++ Conditionals, Ternaries, and Conditional Assignment + If/else statements can be written without the use of parenthesis and + curly brackets. As with functions and other block expressions, conditionals + are closed with periods. No period is necessary when using the single-line + postfix form, with the if at the end. +
+ <%= code_for('conditionals') %> ++ CoffeeScript includes the conditional assignment operators: ||:, + which only assigns a value to a variable if the variable's current value + is falsy, and &&:, which will only replace the value of + truthy variables. +
-- Inheritance, and Calling Super from a Subclass - JavaScript's prototypal inheritance has always been a bit of a - brain-bender, with a whole family tree of libraries (Base2, Prototype - ). -
- <%= code_for('super', true) %> ++ Everything is an Expression (at least, as much as possible) + You might have noticed how even though we don't add return statements + to CoffeScript functions, they nonetheless return their final value. + The CoffeeScript compiler tries to make sure that all statements in the + language can be used as expressions. Watch how the return gets + pushed down into each possible branch of execution, in the function + below. +
+ <%= code_for('expressions', 'eldest') %> ++ The same mechanism is used to push down assignment statements, switch + statements, and if-elses (although the ternary operator is preferred). +
-- Embedded JavaScript - If you ever need to interpolate literal JavaScript snippets, you can - use backticks to pass JavaScript straight through. -
- <%= code_for('embedded', true) %> ++ While Loops + The only low-level loop that CoffeeScript provides is the while loop. +
+ <%= code_for('while') %> ++ Other JavaScript loops, such as for loops and do-while loops + can be mimicked by variations on while, but the hope is that you + won't need to do that with CoffeeScript, either because you're using + each (forEach) style iterators, or... +
-- Switch/Case/Else - Switch statements in JavaScript are fundamentally broken. You can only - do string comparisons, and need to break at the end of each case - statment to prevent falling through to the default case. CoffeeScript - compiles switch statements into if-else chains, allowing you to - compare any object (via ===), preventing fall-through, and resulting - in a returnable expression. -
- <%= code_for('switch') %> ++ Array Comprehensions + For your looping needs, CoffeeScript provides array comprehensions + similar to Python's. They replace (and compile into) for loops, with + optional guard clauses and the value of the current array index. + Unlike for loops, array comprehensions are expressions, and can be returned + and assigned. They should be able to handle most places where you otherwise + would use a loop, each/forEach, map, or select/filter. +
+ <%= code_for('array_comprehensions') %> -- Try/Catch/Finally - Try/catch statements just about the same as JavaScript (although - they work as expressions). No braces required. -
- <%= code_for('try') %> ++ Array Slice Literals + CoffeeScript includes syntax for extracting slices of arrays. + The first argument is the index of the first element in the slice, and + the second is the index of the last one. +
+ <%= code_for('slices', 'three_to_six') %> -- Multiline Strings - Multiline strings are allowed in CoffeeScript. -
- <%= code_for('strings') %> ++ Calling Super from a Subclass + JavaScript's prototypal inheritance has always been a bit of a + brain-bender, with a whole family tree of libraries that provide a cleaner + syntax for classical inheritance on top of JavaScript's prototypes: + Base2, + Prototype.js, + JS.Class, etc. +
+ <%= code_for('super', true) %> -+ Embedded JavaScript + If you ever need to interpolate literal JavaScript snippets, you can + use backticks to pass JavaScript straight through. +
+ <%= code_for('embedded', true) %> + ++ Aliases + Because the == operator frequently causes undesirable coercion, + is intransitive, and has a different meaning than in other languages, + CoffeeScript compiles == into ===, and != into + !==. +
++ is also compiles into ===, + and aint into !==. +
++ +
+ + ++ Switch/Case/Else + Switch statements in JavaScript are fundamentally broken. You can only + do string comparisons, and need to break at the end of each case + statment to prevent falling through to the default case. CoffeeScript + compiles switch statements into if-else chains, allowing you to + compare any object (via ===), preventing fall-through, and resulting + in a returnable expression. +
+ <%= code_for('switch') %> + ++ Try/Catch/Finally + Try/catch statements just about the same as JavaScript (although + they work as expressions). No braces required. +
+ <%= code_for('try') %> + ++ Multiline Strings + Multiline strings are allowed in CoffeeScript. +
+ <%= code_for('strings') %> diff --git a/documentation/js/expressions.js b/documentation/js/expressions.js index 762f9720..9301da9c 100644 --- a/documentation/js/expressions.js +++ b/documentation/js/expressions.js @@ -3,11 +3,7 @@ if (student.excellent_work) { return "A+"; } else if (student.okay_stuff) { - return if (student.tried_hard) { - return "B"; - } else { - return "B-"; - }; + return student.tried_hard ? "B" : "B-"; } else { return "C"; } diff --git a/documentation/js/overview.js b/documentation/js/overview.js new file mode 100644 index 00000000..ee46bfd1 --- /dev/null +++ b/documentation/js/overview.js @@ -0,0 +1,33 @@ +(function(){ + + // Assignment: + var number = 42; + var opposite_day = true; + // Conditions: + if (opposite_day) { + number = -42; + } + // Functions: + var square = function(x) { + return x * x; + }; + // Arrays: + var list = [1, 2, 3, 4, 5]; + // Objects: + var math = { + root: Math.sqrt, + square: square, + cube: function(x) { + return x * square(x); + } + }; + // Array comprehensions: + var cubed_list; + var a = list; + var d = []; + for (var b=0, c=a.length; bCoffeeScript is a little language that compiles into JavaScript. Think - of it as JavaScript's simpleminded kid brother — the same genes, + of it as JavaScript's less ostentatious kid brother — the same genes, the same accent, but a different sense of style. Apart from a handful of - bonus goodies, statements in CoffeeScript correspond one-to-one with their - JavaScript equivalent, it's just another way of saying it. + bonus goodies, statements in CoffeeScript correspond one-to-one with their + equivalent in JavaScript, it's just another way of saying it.
@@ -28,61 +28,230 @@Disclaimer: CoffeeScript is just for fun and seriously alpha. There is no guarantee, - explicit or implied, of its suitability for any purpose. That said, it - compiles into pretty-printed JavaScript (the good parts) that can pass through - JSLint warning-free. + explicit or implied, of its suitability for any purpose. That said, + it compiles into clean JavaScript (the good parts) that can use existing + JavaScript libraries seamlessly, and can pass through + JSLint without warnings. The compiled + scripts are quite readable — pretty-printed, with comments + preserved intact.
- - This document is structured so that it can be read from top to bottom, - if you like. Later sections use ideas and syntax previously introduced. - -
- -
+ Mini Overview
+ Installation and Usage
Punctuation Primer
Functions and Invocation
- Objects and Arrays
Assignment
+ Objects and Arrays
Lexical Scoping and Variable Safety
Conditionals, Ternaries, and Conditional Assignment
Everything is an Expression
While Loops
Array Comprehensions
Array Slice Literals
- Inheritance, and Calling Super from a Subclass
+ Calling Super from a Subclass
Embedded JavaScript
+ Aliases
Switch/Case/Else
Try/Catch/Finally
Multiline Strings
CoffeeScript on the left, compiled JavaScript output on the right.
+ +# Assignment: +number: 42 +opposite_day: true + +# Conditions: +number: -42 if opposite_day + +# Functions: +square: x => x * x. + +# Arrays: +list: [1, 2, 3, 4, 5] + +# Objects: +math: { + root: Math.sqrt + square: square + cube: x => x * square(x). +} + +# Array comprehensions: +cubed_list: math.cube(num) for num in list. +
+// Assignment: +var number = 42; +var opposite_day = true; +// Conditions: +if (opposite_day) { + number = -42; +} +// Functions: +var square = function(x) { + return x * x; +}; +// Arrays: +var list = [1, 2, 3, 4, 5]; +// Objects: +var math = { + root: Math.sqrt, + square: square, + cube: function(x) { + return x * square(x); + } +}; +// Array comprehensions: +var cubed_list; +var a = list; +var d = []; +for (var b=0, c=a.length; b<c; b++) { + var num = a[b]; + d[b] = math.cube(num); +} +cubed_list = d; +
+sudo gem install coffee-script+
- In all of the following examples, the source CoffeeScript is provided on - the left, and the direct compilation into JavaScript is on the right. + Installing the gem provides the coffee-script command, which can + be used to compile CoffeeScript .cs files into JavaScript, as + well as debug. By default, coffee-script writes out the + JavaScript as .js files in the same directory, but output + can be customized with the following options:
--o, --output [DIR] |
+ + Write out all compiled JavaScript files into the specified directory. + | +
-w, --watch |
+ + Watch the modification times of the named scripts, recompiling as + soon as a change occurs. + | +
-p, --print |
+ + Instead of writing out the JavaScript as a file, print it + directly to stdout. + | +
-l, --lint |
+ + If the jsl (JavaScript Lint) command is installed, use it + to check the compilation of a CoffeeScript file. + | +
-e, --eval |
+
+ Compile and print a little snippet of CoffeeScript directly from the
+ command line. For example: coffee-script -e "square: x => x * x." + |
+
-t, --tokens |
+ + Instead of parsing the CoffeeScript, just lex it, and print out the + token stream: [:IDENTIFIER, "square"], [":", ":"], [:PARAM, "x"] ... + | +
-v, --verbose |
+ + As the JavaScript is being generated, print out every step of code + generation, including lexical scope and the node in the + AST. + | +
- Punctuation Primer - You don't need to use semicolons to (;) terminate expressions, ending - the line will do just as well. So newlines can matter, but whitespace is - not otherwise significant. Instead of using curly braces ({ }) - to delimit blocks of code, a period (.) marks the end of a - function, if statement, or try/catch. -
- ++ Examples: +
-- Functions and Invocation - Let's start with the best part, shall we? Function literals are my - absolute favorite thing about CoffeeScript. -
-square: x => x * x. ++coffee-script path/to/script.cs +coffee-script --watch --lint experimental.cs +coffee-script --print app/scripts/*.cs > concatenation.js+ +Language Reference
+ ++ + This document is structured so that it can be read from top to bottom, + if you like. Later sections use ideas and syntax previously introduced. + In all of the following examples, the source CoffeeScript is provided on + the left, and the direct compilation into JavaScript is on the right. + Familiarity with JavaScript is assumed, although it would certainly + be nice to have a tutorial that builds from the ground up in the future. + +
+ ++ Punctuation Primer + You don't need to use semicolons ; to terminate expressions, ending + the line will do just as well. All other whitespace is + not significant. Instead of using curly braces { } + to delimit a block of code, use a period . to mark the end of a + function, if-statement, switch, or try/catch. +
+ ++ Functions and Invocation + Let's start with the best part, shall we? Functions are defined + by a list of parameters, an arrow, and the function body. The empty + function looks like this: =>. +
+-square: x => x * x. cube: x => square(x) * x.var square = function(x) { return x * x; @@ -98,12 +267,28 @@ var cube = function(x) { }; ;alert(cube(5));'>run: cube(5)- Objects and Arrays - Object and Array literals look very similar. When you spread out - each assignment on a separate line, the commas are optional. -
-song: ["do", "re", "mi", "fa", "so"] ++ Assignment + Use a colon : to assign, as in + JSON. Equal signs are only needed for + mathy things. +
++ +greeting: "Hello CoffeeScript" +difficulty: 0.5 +var greeting = "Hello CoffeeScript"; +var difficulty = 0.5; ++ Objects and Arrays + Object and Array literals look very similar to their JavaScript cousins. + When you spread out each assignment on a separate line, the commas are + optional. In this way, assigning object properties looks the same as + assigning local variables. +
+-song: ["do", "re", "mi", "fa", "so"] ages: { max: 10 ida: 9 @@ -122,31 +307,14 @@ var ages = { tim: 11 }; ;alert(song.join(","));'>run: song.join(",")-
-- Assignment - All assignment in CoffeeScript, whether to a variable or to an object - property, uses a colon. Equal signs are only needed for mathy things. -
--greeting: "Hello CoffeeScript" -difficulty: 0.5 -var greeting = "Hello CoffeeScript"; -var difficulty = 0.5; --
- -- Lexical Scoping and Variable Safety - The CoffeeScript compiler takes care to make sure that all of your variables - are properly defined within lexical scope — you never need to declare - var yourself. -
-num: 1 ++ Lexical Scoping and Variable Safety + The CoffeeScript compiler takes care to make sure that all of your variables + are properly defined within lexical scope — you never need to declare + var yourself. +
+-num: 1 change_numbers: => num: 2 new_num: 3. @@ -166,17 +334,28 @@ var change_numbers = function() { }; var new_num = change_numbers(); ;alert(new_num);'>run: new_num- Notice how the variables are declared with var the first time - they appear. The second reference of num, within the function, - is not redeclared because num is still in scope. As opposed - to the second new_num, in the last line. -
++ Notice how the variables are declared with var the first time + they appear. The second reference of num, within the function, + is not redeclared because num is still in scope. As opposed + to the second new_num, in the last line. +
++ Although suppressed within this documentation, all + CoffeeScript output is wrapped in an anonymous function: + (function(){ ... })(); This safety wrapper, combined with the + automatic generation of the var keyword, make it exceedingly difficult + to pollute the global namespace by accident. +
-- Conditionals, Ternaries, and Conditional Assignment -
-mood: greatly_improved if singing ++ Conditionals, Ternaries, and Conditional Assignment + If/else statements can be written without the use of parenthesis and + curly brackets. As with functions and other block expressions, conditionals + are closed with periods. No period is necessary when using the single-line + postfix form, with the if at the end. +
+-mood: greatly_improved if singing if happy and knows_it claps_hands() @@ -196,17 +375,23 @@ expensive ||= do_the_m var date = friday ? sue : jill; expensive = expensive || do_the_math();-
++ CoffeeScript includes the conditional assignment operators: ||:, + which only assigns a value to a variable if the variable's current value + is falsy, and &&:, which will only replace the value of + truthy variables. +
-- Everything is an Expression - You might have noticed how even though we don't add return statements - to CoffeScript functions, they nonetheless return their final value. - The CoffeeScript compiler tries to make sure that every little language - construct can be used as an expression. -
-grade: student => ++ Everything is an Expression (at least, as much as possible) + You might have noticed how even though we don't add return statements + to CoffeScript functions, they nonetheless return their final value. + The CoffeeScript compiler tries to make sure that all statements in the + language can be used as expressions. Watch how the return gets + pushed down into each possible branch of execution, in the function + below. +
+-grade: student => if student.excellent_work "A+" else if student.okay_stuff @@ -219,11 +404,7 @@ eldest: if if (student.excellent_work) { return "A+"; } else if (student.okay_stuff) { - return if (student.tried_hard) { - return "B"; - } else { - return "B-"; - }; + return student.tried_hard ? "B" : "B-"; } else { return "C"; } @@ -233,30 +414,23 @@ eldest: if 21 ? "Liz" : "Ike"; ;alert(eldest);'>run: eldest- When compiling a function definition, CoffeeScript tries to push down - the return statement to each of the potential final lines of the function. - It uses the same mechanism to push down assignment statements. If statement - are compiled into ternary operators when possible, so that they can be used - as expressions. -
++ The same mechanism is used to push down assignment statements, switch + statements, and if-elses (although the ternary operator is preferred). +
-- While Loops - The only low-level loop that CoffeeScript provides is the while loop. -
-while demand > supply ++ While Loops + The only low-level loop that CoffeeScript provides is the while loop. +
++while demand > supply sell() restock(). @@ -269,16 +443,23 @@ var eldest = 24 > 21 ? "Liz" : "Ike"; buy(); }+ Other JavaScript loops, such as for loops and do-while loops + can be mimicked by variations on while, but the hope is that you + won't need to do that with CoffeeScript, either because you're using + each (forEach) style iterators, or... +
-- Array Comprehensions - Most of your looping needs should be handled by array comprehensions. - They replace (and compile into) for loops, handling - each/forEach style loops, as well as select/filter. - Unlike for loops, array comprehensions are expressions, and can be returned - and assigned. -
-# Eat lunch. ++ Array Comprehensions + For your looping needs, CoffeeScript provides array comprehensions + similar to Python's. They replace (and compile into) for loops, with + optional guard clauses and the value of the current array index. + Unlike for loops, array comprehensions are expressions, and can be returned + and assigned. They should be able to handle most places where you otherwise + would use a loop, each/forEach, map, or select/filter. +
+-# Eat lunch. lunch: food.eat() for food in ['toast', 'cheese', 'wine']. # Zebra-stripe a table. @@ -302,13 +483,13 @@ lunch = d; }- Array Slice Literals - CoffeeScript includes a literal syntax for extracting slices of arrays. - The first argument is the index of the first element in the slice, and - the second is the index of the last one. -
-nums: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ++ Array Slice Literals + CoffeeScript includes syntax for extracting slices of arrays. + The first argument is the index of the first element in the slice, and + the second is the index of the last one. +
+-nums: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] three_to_six: nums[3, 6]var nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; var three_to_six = nums.slice(3, 6 + 1); @@ -316,13 +497,16 @@ three_to_six: nums[3, < var three_to_six = nums.slice(3, 6 + 1); ;alert(three_to_six);'>run: three_to_six- Inheritance, and Calling Super from a Subclass - JavaScript's prototypal inheritance has always been a bit of a - brain-bender, with a whole family tree of libraries (Base2, Prototype - ). -
-Animal: => . ++ Calling Super from a Subclass + JavaScript's prototypal inheritance has always been a bit of a + brain-bender, with a whole family tree of libraries that provide a cleaner + syntax for classical inheritance on top of JavaScript's prototypes: + Base2, + Prototype.js, + JS.Class, etc. +
+-Animal: => . Animal.prototype.move: meters => alert(this.name + " moved " + meters + "m."). @@ -395,12 +579,12 @@ sam.move(); tom.move(); ;'>run- Embedded JavaScript - If you ever need to interpolate literal JavaScript snippets, you can - use backticks to pass JavaScript straight through. -
-js: => `alert("Hello JavaScript");`. ++ Embedded JavaScript + If you ever need to interpolate literal JavaScript snippets, you can + use backticks to pass JavaScript straight through. +
+-js: => `alert("Hello JavaScript");`. js() if 10 > 9var js = function() { @@ -417,16 +601,32 @@ if (10 > 9) { } ;'>run- Switch/Case/Else - Switch statements in JavaScript are fundamentally broken. You can only - do string comparisons, and need to break at the end of each case - statment to prevent falling through to the default case. CoffeeScript - compiles switch statements into if-else chains, allowing you to - compare any object (via ===), preventing fall-through, and resulting - in a returnable expression. -
-switch day ++ Aliases + Because the == operator frequently causes undesirable coercion, + is intransitive, and has a different meaning than in other languages, + CoffeeScript compiles == into ===, and != into + !==. +
++ is also compiles into ===, + and aint into !==. +
++ +
+ + ++ Switch/Case/Else + Switch statements in JavaScript are fundamentally broken. You can only + do string comparisons, and need to break at the end of each case + statment to prevent falling through to the default case. CoffeeScript + compiles switch statements into if-else chains, allowing you to + compare any object (via ===), preventing fall-through, and resulting + in a returnable expression. +
+-switch day case "Tuesday" then eat_breakfast() case "Wednesday" then go_to_the_park() case "Saturday" @@ -438,9 +638,7 @@ if (10 > 9) { } else if (day === "Wednesday") { go_to_the_park(); } else if (day === "Saturday") { - if (day === bingo_day) { - go_to_bingo(); - }; + day === bingo_day ? go_to_bingo() : null; } else if (day === "Sunday") { go_to_church(); } else { @@ -448,16 +646,16 @@ if (10 > 9) { }- Try/Catch/Finally - Try/catch statements just about the same as JavaScript (although - they work as expressions). No braces required. -
-try ++ Try/Catch/Finally + Try/catch statements just about the same as JavaScript (although + they work as expressions). No braces required. +
+-try all_hell_breaks_loose() cats_and_dogs_living_together() catch error - print( error ) + print(error) finally clean_up().try { @@ -470,11 +668,11 @@ if (10 > 9) { }
- Multiline Strings - Multiline strings are allowed in CoffeeScript. -
--moby_dick: "Call me Ishmael. Some years ago -- ++ Multiline Strings + Multiline strings are allowed in CoffeeScript. +
+-moby_dick: "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail @@ -488,8 +686,6 @@ if (10 > 9) { world...";