Coffeescript Javascript the good parts
Sebastian Deutsch http://9elements.com Follow me on Twitter: http://twitter.com/sippndipp sebastian.deutsch@9elemtents.com
Wenn ich JAVA höre,
dann sehe ich...
Als ich angefangen habe, wollte ich aber eher so sein...
Be a Rebel Jede Kultur hat ihre Rebellen Jede Kultur hat ihr Imperium
...die Seiten wechseln ist nicht schlimm
Am JavaScript Day bin ich der CoffeeScript Rebel
Was ist CoffeeScript CoffeeScript ist ein Präprozessor für JS Alternative Syntax Forciert expressiven Code
Was ist CoffeeScript CoffeeScript ist Compiler Nutzt Jison Als Node.js Utility verfügbar
Getting started npm install coffee-script brew install coffee-script coffee --version
Zutaten
Significant Whitespace Kulturschock: Blöcke = Indentation Alles sind Expressions Das letzte evaluierte Objekt wird zurückgegeben
Beispiel JavaScript var cube, square; square = function(x) { return x * x; }; cube = function(x) { return square(x) * x; };
Beispiel JavaScript square = function(x) return x * x cube = function(x) return square(x) * x Implizite Deklaration von Variablen Keine Klammern, keine Semikolons
Beispiel JavaScript square = (x) -> x * x cube = (x) -> square(x) * x Funktion Keyword durch -> ersetzen Der letze evaluierte Wert wird zurückgegeben
CoffeScript...
...entfernt visuellen Lärm
OK Was noch?
Variablen CoffeeScript: number = 42 opposite = true alpha = ["a","b","c"] bitlist = [ 1, 0, 1 ] 0, 0, 1 1, 1, 0 JavaScript: var alpha, bitlist, number, opposite; number = 42; opposite = true; alpha = ["a", "b", "c"]; bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];
Kontrollstrukturen number = -42 if opposite number = 1337 unless no_hacker if happy and knowsit claps_hands() do cha_cha_cha else show_it() Bedingungen können wie in Ruby eingesetzt werden
Switch switch day when "mon" then go "work" when "tue" then go "relax" when "thu" then go "ice fishing" when "fri", sat if "day" is "bingo_day" go "bingo" go "dancing" when "sun" then go "church" else go "work" go ist eine Funktion, Klammern müssen nicht sein
Try/Catch try all_hell_breaks_loose() cats_and_dogs_living_together() catch error console.log error finally clean_up() go ist eine Funktion, Klammern müssen nicht sein
Objekte (Hashes) singers = { Jagger: "Rock", Elvis: "Roll" } # YML style kids = brother: name: "Max" age: 11 sister: name: "Ida" age: 9
Schleifen CoffeeScript: goods = [ bread, 'wine'] eat food for food in goods JavaScript: var food, goods, _i, _len; goods = [ bread, 'wine']; for (_i = 0, _len = goods.length; _i < _len; _i++) { } food = goods[_i]; eat(food); Array Komprehension ist implizit, Schleifen sind Expressions
While/Until CoffeeScript: if this.studying_economics buy() while supply > demand sell() until supply > demand JavaScript: if (this.studying_economics) { while (supply > demand) { buy(); } while ((supply > demand)) { } } sell();
Spice
Array Comprehension for roid in asteroids for roid2 in asteroids when roid isnt roid2 roid.explode() if roid.overlaps roid2
Array Comprehension var roid, roid2, _i, _j, _len, _len2; for (_i = 0, _len = asteroids.length; _i < _len; _i++) { roid = asteroids[_i]; for (_j = 0, _len2 = asteroids.length; _j < _len2; _j++) { roid2 = asteroids[_j]; if (roid == roid2) { if (roid.overlaps(roid2)) { roid.explode(); } } } } 3 Zeilen vs. 12 Zeilen ;-)
Classes class Animal constructor: (@name) -> move: (meters) -> alert @name + " moved " + meters + "m." class Snake extends Animal move: -> alert "Slithering..." super 5 class Horse extends Animal move: -> alert "Galloping..." super 45 sam = new Snake "Sammy the Python" tom = new Horse "Tommy the Palomino" sam.move() tom.move()
Classes: Behind the Scenes extend function Prototypische Vererbung Jedes Objekt hat ein super Attribut
Classes: Behind the Scenes @ shortcut für this Innerhalb von Funktionen = Instanzvariablen Innerhalb von Hashes = statische Variablen
Open Classes Coffeescript: String::dasherize = -> @replace /_/g, - Javascript: String.prototype.dasherize = function() { return this.replace(/_/g, - ); };
Fat Arrow Coffeescript: Account = (customer, cart) -> @customer = customer @cart = cart $('.shopping_cart').bind 'click', (event) => @customer.purchase @cart
Fat Arrow Javascript: var Account; var bind = function(fn, me) { return function(){ return fn.apply(me, arguments); }; }; Account = function(customer, cart) { this.customer = customer(this.cart = cart); return $('.shopping_cart').bind('click', bind(function(event) { return this.customer.purchase(this.cart); }, this)); };
String Interpolation author = "Wittgenstein quote = "A picture is a fact. -- #{author}" String Interpolation wie bei Ruby, kann auch eine Expression sein.
Splats Coffeescript: race = (winner, runners...) -> console.log winner, runners Javascript: race = function() { var runners, winner; winner = arguments[0], runners = 2 <= arguments.length? slice.call(arguments, 1) : []; return console.log(winner, runners); };
Existence Coffeescript: alert "I knew it" if elvis? speed?= 140 lottery.draw_winner()?.address?.zipcode Ähnlich wie der AndAnd Gem bei Ruby oder try in Rails.
Existence Javascript: var _ref, _ref2; if (typeof elvis = "undefined" && elvis == null) { alert("i knew it"); } typeof speed = "undefined" && speed == null? speed : speed = 140; if ((_ref = lottery.drawwinner()) = null) { if ((_ref2 = _ref.address) = null) { _ref2.zipcode; } }
Destructuring Assignemnt weatherreport = (location) -> [location, 26, Sonnig"] [city, temp, forecast] = weatherreport Frankfurt"
Aliase is compiles to === isnt compiles to == not compiles to and compiles to && or compiles to on, yes, true compile to true off, no, false compile to false @, this compile to this of compile to in
Chained Comparisons cholesterol = 127 healthy = 200 > cholesterol > 60 Bei Python ausgeliehen
/Stand back I know regular Expressions/
Extended RegExp # Interpolation sep = "[.\\/\\- ] dates = /\d+#{sep}\d+#{sep}\d+/g # Extended RegExp OPERATOR = /// ^ (?: [-=]> # function [-+*/%<>& ^?=]= # compound assign / compare >>>=? # zero-fill right shift ([-+:])\1 # doubles ([& <>])\2=? # logic / shift \?\. # soak access \.{2,3} # range or splat ) ///
Toolchain
Editor TextMate Bundle http://github.com/ jashkenas/coffeescript-tmbundle VIM http://github.com/ kchmck/vim-coffeescript Emacs http://github.com/ defunkt/coffee-mode IntelliJ IDEA http:// yeungda.github.com /coffeescript-idea/
Cakefile sys = require 'sys' fs = require 'fs' exec = require('child_process').exec spawn = require('child_process').spawn task 'watch', 'watches and compiles coffee', -> sys.print "Spawning coffee watcher" coffee = spawn 'coffee', ['-cw', '-o', 'lib', 'src'] coffee.stdout.on 'data', (data) -> sys.print data exec "growlnotify -m \"#{data}\" -t \"Cakefile\"" coffee.stderr.on 'data', (data) -> sys.print data exec "growlnotify -m \"#{data}\" -t \"Cakefile\""
Rails 3.1 macht Coffeescript zum Default
Rails 3.1 https://github.com/rails/rails/compare/ 9333ca7...23aa7da Love It... I wish I could be constructive, but CofffeScript makes me nerdrage.
Thank You
one more thing
We re hiring contact@9elements.com