Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CoffeeScript: A New Brew

CoffeeScript: A New Brew

Ruby developers will find CoffeeScript to be a great alternative to JavaScript, with a lot of familiar language features. This talk introduces CoffeeScript by starting with JavaScript, then ripping out the cruft and ceremony. (WindyCityRails 2011)

David Kinney

May 20, 2012
Tweet

More Decks by David Kinney

Other Decks in Programming

Transcript

  1. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  2. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  3. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  4. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  5. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  6. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  7. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  8. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  9. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  10. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  11. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  12. My History with JS 1995 JS released It’s not Applets!

    YAY! 1996–2003 DHTML fails Meh. 2004–2009 GMail, Google Maps, jQuery Ajax! YAY! Present MVC in the browser Meh.
  13. What’s Wrong with JS? • function • return • var

    • == • for • prototype-based OO
  14. What’s Right with JS? • closures / blocks • namespaces

    • loosely typed variables • evented instead of threaded
  15. Starting Over Today • Just give me the good parts

    • …and improve the expressiveness of business logic
  16. Starting Over Today • Just give me the good parts

    • …and improve the expressiveness of business logic • …but let me interoperate with all the existing great JS libraries
  17. Whirlwind Tour var intersection = function(ary1, ary2) { if (ary1.length

    > ary2.length) { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; }
  18. Whirlwind Tour var intersection = function(ary1, ary2) { if (ary1.length

    > ary2.length) { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; }
  19. Whirlwind Tour var intersection = function(ary1, ary2) { if (ary1.length

    > ary2.length) { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; }
  20. var intersection = function(ary1, ary2) { if (ary1.length > ary2.length)

    { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; } Whirlwind Tour
  21. var intersection = function(ary1, ary2) { if (ary1.length > ary2.length)

    { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; } Whirlwind Tour
  22. var intersection = function(ary1, ary2) { if (ary1.length > ary2.length)

    { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; } Whirlwind Tour X X X X X
  23. var intersection = function(ary1, ary2) { if (ary1.length > ary2.length)

    { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; } Whirlwind Tour X X X X X X X
  24. var intersection = function(ary1, ary2) { if (ary1.length > ary2.length)

    { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; } Whirlwind Tour X X X X X X X X X X X X X
  25. var intersection = function(ary1, ary2) { if (ary1.length > ary2.length)

    { var tmp = ary1; ary1 = ary2; ary2 = tmp; } var out = []; for (var i=0; i<ary1.length; ++i) { var val = ary1[i]; if (ary2.indexOf(val) >= 0) out.push(val); } return out; } Whirlwind Tour X X X X X X X X X X X X X X X X X X
  26. Whirlwind Tour intersection = (ary1, ary2) if (ary1.length > ary2.length)

    tmp = ary1; ary1 = ary2; ary2 = tmp out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  27. Whirlwind Tour intersection = (ary1, ary2) if (ary1.length > ary2.length)

    tmp = ary1; ary1 = ary2; ary2 = tmp out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out ->
  28. Whirlwind Tour intersection = (ary1, ary2) -> if (ary1.length >

    ary2.length) tmp = ary1; ary1 = ary2; ary2 = tmp out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  29. Whirlwind Tour intersection = (ary1, ary2) -> if (ary1.length >

    ary2.length) tmp = ary1; ary1 = ary2; ary2 = tmp out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  30. Whirlwind Tour intersection = (ary1, ary2) -> if (ary1.length >

    ary2.length) tmp = ary1; ary1 = ary2; ary2 = tmp out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  31. Whirlwind Tour intersection = (ary1, ary2) -> if ary1.length >

    ary2.length tmp = ary1; ary1 = ary2; ary2 = tmp out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  32. Whirlwind Tour intersection = (ary1, ary2) -> if ary1.length >

    ary2.length [ary2,ary1] = [ary1,ary2] out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  33. Whirlwind Tour intersection = (ary1, ary2) -> out = []

    for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out if ary1.length > ary2.length [ary2,ary1] = [ary1,ary2]
  34. Whirlwind Tour intersection = (ary1, ary2) -> out = []

    for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out if ary1.length > ary2.lengt [ary2,ary1] = [ary1,ary2]
  35. Whirlwind Tour intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2]

    if ary1.length > ary2.l out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  36. Whirlwind Tour intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2]

    if ary1.length > ary2.l out = [] for (i=0; i<ary1.length; ++i) val = ary1[i] if (ary2.indexOf(val) >= 0) out.push(val) out
  37. Whirlwind Tour intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2]

    if ary1.length > ary2.l out = (x for x in ary1 when ary2.indexOf(x) >= 0) out
  38. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l out = (x for x in ary1 when ary2.indexOf(x) >= 0) out Whirlwind Tour ary1.
  39. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l out = (x for x in ary1 when ary2.indexOf(x) >= 0) out Whirlwind Tour select { |x| ary2.indexOf(x) >= 0 }. ary1.
  40. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l out = (x for x in ary1 when ary2.indexOf(x) >= 0) out Whirlwind Tour select { |x| ary2.indexOf(x) >= 0 }. ary1. map { |x| x }
  41. Whirlwind Tour intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2]

    if ary1.length > ary2.l out = (x for x in ary1 when ary2.indexOf(x) >= 0) out
  42. Whirlwind Tour intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2]

    if ary1.length > ary2.l out = (x for x in ary1 when ary2.indexOf(x) >= 0) out when x in ary2)
  43. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l Whirlwind Tour out = out (x for x in ary1 when x in ary2)
  44. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l Whirlwind Tour (x for x in ary1 when x in ary2)
  45. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l (x for x in ary1 when x in ary2) Whirlwind Tour
  46. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l (x for x in ary1 when x in ary2) Whirlwind Tour
  47. intersection = (ary1, ary2) -> [ary2,ary1] = [ary1,ary2] if ary1.length

    > ary2.l (x for x in ary1 when x in ary2) Whirlwind Tour
  48. Whirlwind var intersection; var __indexOf = Array.prototype.indexOf || function(item) {

    for (var i = 0, l = this.length; i < l; i++) { if (this[i] === item) return i; } return -1; }; intersection = function(ary1, ary2) { var x, _i, _len, _ref, _results; if (ary1.length > ary2.l) { _ref = [ary1, ary2], ary2 = _ref[0], ary1 = _ref[1]; } _results = []; for (_i = 0, _len = ary1.length; _i < _len; _i++) { x = ary1[_i]; if (__indexOf.call(ary2, x) >= 0) { _results.push(x); } } return _results; }; JavaScript
  49. Functions say_hello = -> "Hello, world" # same as say_hello

    = -> "Hello, world" # invoked with say_hello()
  50. Functions say_hello = -> "Hello, world" # same as say_hello

    = -> "Hello, world" # invoked with say_hello() // compiles to: var say_hello; say_hello = function() { return "Hello, world"; }; say_hello();
  51. Functions say_hello = (name) -> "Hello, #{name}" say_hello("David") say_hello "David"

    // compiles to: var say_hello; say_hello = function(name) { return "Hello, " + name; }; say_hello("David"); say_hello("David");
  52. Classes class Person constructor: (first_name, last_name) -> this.first_name = first_name

    this.last_name = last_name full_name: -> "#{this.first_name} #{this.last_name}"
  53. Classes class Person constructor: (first_name, last_name) -> @first_name = first_name

    @last_name = last_name full_name: -> "#{@first_name} #{@last_name}"
  54. Classes class Person constructor: (first_name, last_name) -> @first_name = first_name

    @last_name = last_name full_name: -> "#{@first_name} #{@last_name}"
  55. Classes class Person constructor: (@first_name, @last_name) -> full_name: -> "#{@first_name}

    #{@last_name}" // compiles to: var Person; Person = (function() { function Person(first_name, last_name) { this.first_name = first_name; this.last_name = last_name; } Person.prototype.full_name = function() { return "" + this.first_name + " " + this.last_name; }; return Person; })();
  56. class Person constructor: (@first_name, @last_name) -> full_name: -> "#{@first_name} #{@last_name}"

    class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" Classes: Inheritance
  57. class Person constructor: (@first_name, @last_name) -> full_name: -> "#{@first_name} #{@last_name}"

    class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" // "class Employee extends Person" compiles to: var Employee; var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; Employee = (function() { __extends(Employee, Person); function Employee() { Employee.__super__.constructor.apply(this, arguments); } return Employee; })(); Classes: Inheritance
  58. class Person constructor: (@first_name, @last_name) -> full_name: -> "#{@first_name} #{@last_name}"

    class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" Classes: Inheritance
  59. class Person constructor: (@first_name, @last_name) -> full_name: -> "#{@first_name} #{@last_name}"

    class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" employee = new Employee("Tim", "Cook", "CEO") console.log employee.full_name() # prints "Tim Cook, CEO" Classes: Inheritance
  60. Classes: Fat Arrow class PersonController constructor: (@person) -> display_person: ->

    $('#person_name').text(@person.full_name) person = # loaded from server
  61. Classes: Fat Arrow class PersonController constructor: (@person) -> display_person: ->

    $('#person_name').text(@person.full_name) person = # loaded from server controller = new PersonController(person)
  62. Classes: Fat Arrow class PersonController constructor: (@person) -> display_person: ->

    $('#person_name').text(@person.full_name) person = # loaded from server controller = new PersonController(person) $('button').click controller.display_person # FAIL!
  63. Classes: Fat Arrow class PersonController constructor: (@person) -> display_person: ->

    $('#person_name').text(@person.full_name) => person = # loaded from server controller = new PersonController(person) $('button').click controller.display_person # FAIL!
  64. 1 == '1' // true 1 == '1.0' // true

    1 == true // true Comparisons JavaScript
  65. 1 == '1' // true 1 == '1.0' // true

    1 == true // true Comparisons JavaScript 1 === '1.0' // false 1 === '1' // false
  66. 1 == '1' // true 1 == '1.0' // true

    1 == true // true Comparisons JavaScript 1 === '1.0' // false 1 === '1' // false 1 is '1' # false 1 is '1.0' # false 1 is true # false 1 is 1 # true 1 is 1.0 # true CoffeeScript
  67. is odd = num % 2 is 1 isnt apple_rejection

    = app_lang isnt "Objective-C" in toddler = age in [1,2,3] not even = not odd and never_true = even and odd or fun = ruby or coffee_script Comparisons
  68. Existential Operator $('#name').text(person.full_name) if person? person ?= new Person("David", "Kinney")

    beneficiary = spouse ? daughter zip = lottery.drawWinner?().address?.zipcode
  69. Switch switch day when "Mon" then go work when "Tue"

    then go relax when "Thu" then go iceFishing when "Fri", "Sat" if day is bingoDay go bingo go dancing when "Sun" then go church else go work
  70. Stuff with Objects yearsOld = alice: 10, bob: 9, charlie:

    11 ages = for child, age of yearsOld "#{child} is #{age}"
  71. Destructuring Objects futurists = sculptor: "Umberto Boccioni" painter: "Vladimir Burliuk"

    poet: name: "F.T. Marinetti" address: [ "Via Roma 42R" "Bellagio, Italy 22021" ] # extract name, street, and city {poet: {name, address: [street, city]}} = futurists
  72. Rails 3.1 $ -> more_link = $('<span></span>') more_link.addClass 'more-link' more_link.text

    'more' more_link.click -> $('#full-text').slideDown() $('#full-text').before(more_link).hide() app/assets/javascript/more_expander.js.coffee
  73. Rails 3.1 class Person constructor: (@first_name, @last_name) -> full_name: ->

    "#{@first_name} #{@last_name}" app/assets/javascript/person.js.coffee
  74. Rails 3.1 class Person constructor: (@first_name, @last_name) -> full_name: ->

    "#{@first_name} #{@last_name}" app/assets/javascript/person.js.coffee class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" app/assets/javascript/employee.js.coffee
  75. Rails 3.1 class Person constructor: (@first_name, @last_name) -> full_name: ->

    "#{@first_name} #{@last_name}" app/assets/javascript/person.js.coffee class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" app/assets/javascript/employee.js.coffee window.Person = Person unless window.Person?
  76. Rails 3.1 class Person constructor: (@first_name, @last_name) -> full_name: ->

    "#{@first_name} #{@last_name}" app/assets/javascript/person.js.coffee class Employee extends Person constructor: (first, last, @title) -> super(first, last) full_name: -> "#{super}, #{@title}" app/assets/javascript/employee.js.coffee window.Person = Person unless window.Person? window.Employee = Employee unless window.Employee?