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

CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again

CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again

FOWA 2011

Sam Stephenson

October 05, 2011
Tweet

Other Decks in Programming

Transcript

  1. View Slide

  2. Sam Stephenson
    37signals

    View Slide

  3. Better JavaScript
    with CoffeeScript

    View Slide

  4. CoffeeScript is
    Beautiful & I Never
    Want to Write Plain
    JavaScript Again

    View Slide

  5. A Brief Personal History

    View Slide

  6. 2004

    View Slide

  7. names =
    people.map do |person|
    person.name.capitalize
    end

    View Slide

  8. var names = [];
    for (var i = 0, l = people.length;
    i < l; i++) {
    var person = people[i];
    var name = person.name.
    slice(0, 1).toUpperCase() +
    person.name.slice(1);
    names.push(name);
    }

    View Slide

  9. .
    prototype
    .

    View Slide

  10. var names = people.map(
    function(person) {
    return person.name.
    capitalize();
    }
    );

    View Slide

  11. var names = people.map(
    function(person) {
    return person.name.
    capitalize();
    }
    );

    View Slide

  12. var names = people.map(
    function(person) {
    return person.name.
    capitalize();
    }
    );

    View Slide

  13. 2010

    View Slide

  14. We’re Stuck With JavaScript

    View Slide

  15. Compile to JavaScript

    View Slide

  16. Google Web Toolkit

    View Slide

  17. package com.example.gwt.helloworld.client;
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.event.dom.client.ClickEvent;
    import com.google.gwt.event.dom.client.ClickHandler;
    import com.google.gwt.user.client.Window;
    import com.google.gwt.user.client.ui.Button;
    import com.google.gwt.user.client.ui.Label;
    import com.google.gwt.user.client.ui.RootPanel;
    public class HelloWorld implements EntryPoint {
    @Override
    public void onModuleLoad() {
    Label label = new Label("Hello world");
    Button button = new Button("Say something");
    button.addClickHandler(new ClickHandler() {
    @Override
    public void onClick(ClickEvent event) {
    Window.alert("Hello again");
    }
    });
    RootPanel.get().add(label);
    RootPanel.get().add(button);
    }
    }

    View Slide










  18. PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">



    Com_example_gwt_helloworld.html


    View Slide

  19. View Slide

  20. function hello(){var l='',F='" for "gwt:onLoadErrorFn"',D='" for "gwt:onPropert
    yErrorFn"',n='"><\/script>',p='#',r='/',vb='02EDD05CEF7D978C649BF91CC66AB635.ca
    che.html',sb='28600060343BDDEB1FD83487846D090C.cache.html',ub='9EDF9C067C3A475F
    6EA7A16003CA4979.cache.html',Fb='hello.onInjectionDone(\'<br/>hello\')<\/script>',dc='<script id="',A='=',q='?',C='Bad handler "',tb='D69BADE<br/>681FFFC6071DFA4FC25EF1DC5.cache.html',Eb='DOMContentLoaded',wb='F26BFE33DA14C23<br/>176C7BC08D58AA43F.cache.html',o='SCRIPT',cc='__gwt_marker_hello',s='base',nb='b<br/>egin',cb='bootstrap',u='clear.cache.gif',z='content',bc='end',lb='gecko',mb='ge<br/>cko1_8',yb='gwt.hybrid',xb='gwt/standard/standard.css',E='gwt:onLoadErrorFn',B=<br/>'gwt:onPropertyErrorFn',y='gwt:property',Db='head',qb='hosted.html?hello',Cb='h<br/>ref',kb='ie6',ab='iframe',t='img',bb="javascript:''",zb='link',pb='loadExternal<br/>Refs',v='meta',eb='moduleRequested',ac='moduleStartup',jb='msie',w='name',gb='o<br/>pera',db='position:absolute;width:0;height:0;border:none',Ab='rel',ib='safari',<br/>rb='selectingPermutation',x='startup',m='hello',Bb='stylesheet',ob='unknown',fb<br/>='user.agent',hb='webkit';var fc=window,k=document,ec=fc.__gwtStatsEvent?functi<br/>on(a){return fc.__gwtStatsEvent(a)}:null,zc,pc,kc,jc=l,sc={},Cc=[],yc=[],ic=[],<br/>vc,xc;ec&&ec({moduleName:m,subSystem:x,evtGroup:cb,millis:(new Date()).getTime(<br/>),type:nb});if(!fc.__gwt_stylesLoaded){fc.__gwt_stylesLoaded={}}if(!fc.__gwt_sc<br/>riptsLoaded){fc.__gwt_scriptsLoaded={}}function oc(){var b=false;try{b=fc.exter<br/>nal&&(fc.external.gwtOnLoad&&fc.location.search.indexOf(yb)==-1)}catch(a){}oc=f<br/>unction(){return b};return b}function rc(){if(zc&&pc){var c=k.getElementById(m)<br/>;var b=c.contentWindow;if(oc()){b.__gwt_getProperty=function(a){return lc(a)}}h<br/>ello=null;b.gwtOnLoad(vc,m,jc);ec&&ec({moduleName:m,subSystem:x,evtGroup:ac,mil<br/>lis:(new Date()).getTime(),type:bc})}};function mc(){var j,h=cc,i;k.write(dc+h+<br/>n);i=k.getElementById(h);j=i&&i.previousSibling;while(j&&j.tagName!=o){j=j.prev<br/>iousSibling}function f(b){var a=b.lastIndexOf(p);if(a==-1){a=b.length}var c=b.i<br/>ndexOf(q);if(c==-1){c=b.length}var d=b.lastIndexOf(r,Math.min(c,a));return d>=0<br/>?b.substring(0,d+1):l};if(j&&j.src){jc=f(j.src)}if(jc==l){var e=k.getElementsBy<br/>TagName(s);if(e.length>0){jc=e[e.length-1].href}else{jc=f(k.location.href)}}els<br/>e if(jc.match(/^\w+:\/\//)){}else{var g=k.createElement(t);g.src=jc+u;jc=f(g.sr<br/>

    View Slide

  21. Pyjamas

    View Slide

  22. import pyjd # this is dummy in pyjs.
    from pyjamas.ui.RootPanel import RootPanel
    from pyjamas.ui.Button import Button
    from pyjamas.ui.HTML import HTML
    from pyjamas.ui.Label import Label
    from pyjamas import Window
    import pygwt
    def greet(fred):
    fred.setText("No, really click me!")
    Window.alert("Hello, AJAX!")
    if __name__ == '__main__':
    pyjd.setup("public/Hello.html?fred=foo#me")
    b = Button("Click me", greet, StyleName='teststyle')
    h = HTML("Hello World (html)", StyleName='teststyle')
    l = Label("Hello World (label)", StyleName='teststyle')
    base = HTML("Hello from %s" % pygwt.getModuleBaseURL(),
    StyleName='teststyle')
    RootPanel().add(b)
    RootPanel().add(h)
    RootPanel().add(l)
    RootPanel().add(base)
    pyjd.run()

    View Slide

  23. I love/prefer {insert AJAX / Javascript framework here},
    how do I use it?
    Not being funny or anything, but unless you have the
    resources of google or lots of money or lots of time, or you
    can gather enough people to make it so that everyone has
    less work to do: you don't.
    huh? why?? Some of the widgets in DojoX / Ext-JS are
    really cute! I want them! waaah!
    You are not in Kansas any more. Pyjamas is declarative-
    style programming, using a "real" programming language.
    All those widget-sets were designed to be driven from
    inside HTML (a style of web development which, using
    Pyjamas, you have just left far behind) and by inserting
    javascript snippets into the HTML. If you try that with a
    Pyjamas app, you are not only likely to get yourself into an

    View Slide

  24. I love/prefer {insert AJAX / Javascript framework here},
    how do I use it?
    Not being funny or anything, but unless you have the
    resources of google or lots of money or lots of time, or you
    can gather enough people to make it so that everyone has
    less work to do: you don't.
    huh? why?? Some of the widgets in DojoX / Ext-JS are
    really cute! I want them! waaah!
    You are not in Kansas any more. Pyjamas is declarative-
    style programming, using a "real" programming language.
    All those widget-sets were designed to be driven from
    inside HTML (a style of web development which, using
    Pyjamas, you have just left far behind) and by inserting
    javascript snippets into the HTML. If you try that with a
    Pyjamas app, you are not only likely to get yourself into an

    View Slide

  25. I love/prefer {insert AJAX / Javascript framework here},
    how do I use it?
    Not being funny or anything, but unless you have the
    resources of google or lots of money or lots of time, or you
    can gather enough people to make it so that everyone has
    less work to do: you don't.
    huh? why?? Some of the widgets in DojoX / Ext-JS are
    really cute! I want them! waaah!
    You are not in Kansas any more. Pyjamas is declarative-
    style programming, using a "real" programming language.
    All those widget-sets were designed to be driven from
    inside HTML (a style of web development which, using
    Pyjamas, you have just left far behind) and by inserting
    javascript snippets into the HTML. If you try that with a
    Pyjamas app, you are not only likely to get yourself into an

    View Slide

  26. Objective-J

    View Slide

  27. @implementation AppController : CPObject { }
    - (void)applicationDidFinishLaunching:(CPNotification)note
    {
    theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero()
    styleMask:CPBorderlessBridgeWindowMask];
    contentView = [theWindow contentView];
    var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
    [label setStringValue:@"Hello World!"];
    [label setFont:[CPFont boldSystemFontOfSize:24.0]];
    [label sizeToFit];
    [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
    [label setFrameOrigin:CGRectMake(100,100)];
    [contentView addSubview:label];
    [theWindow orderFront:self];
    }
    @end

    View Slide

  28. View Slide

  29. CoffeeScript is a little language that
    compiles into JavaScript.
    Underneath all of those embarrassing
    braces and semicolons, JavaScript has
    always had a gorgeous object model
    at its heart. CoffeeScript is an attempt
    to expose the good parts of JavaScript
    in a simple way.
    The golden rule of CoffeeScript is: “It’s
    just JavaScript”. The code compiles
    one-to-one into the equivalent JS, and
    there is no interpretation at runtime.

    View Slide

  30. CoffeeScript is a little language that
    compiles into JavaScript.
    Underneath all of those embarrassing
    braces and semicolons, JavaScript has
    always had a gorgeous object model
    at its heart. CoffeeScript is an attempt
    to expose the good parts of JavaScript
    in a simple way.
    The golden rule of CoffeeScript is: “It’s
    just JavaScript”. The code compiles
    one-to-one into the equivalent JS, and
    there is no interpretation at runtime.

    View Slide

  31. It’s Just JavaScript
    $(function() {
    $("body").html("Hello world");
    });

    View Slide

  32. It’s Just JavaScript
    $ ->
    $("body").html "Hello world"

    View Slide

  33. CoffeeScript is a little language that
    compiles into JavaScript.
    Underneath all of those embarrassing
    braces and semicolons, JavaScript has
    always had a gorgeous object model
    at its heart. CoffeeScript is an attempt
    to expose the good parts of JavaScript
    in a simple way.
    The golden rule of CoffeeScript is: “It’s
    just JavaScript”. The code compiles
    one-to-one into the equivalent JS, and
    there is no interpretation at runtime.

    View Slide

  34. View Slide

  35. View Slide

  36. Good Part:
    Private by default

    View Slide

  37. Good Part:
    Private by default
    (function() {
    /* your program here */
    }).call(this);

    View Slide

  38. Good Part:
    No more var

    View Slide

  39. Good Part:
    No more var
    lastClick = 0
    $("a").click ->
    now = new Date().getTime()
    if now - lastClick > 100
    $("#message").show()
    lastClick = now

    View Slide

  40. Good Part:
    No more var
    var lastClick = 0
    $("a").click ->
    var now = new Date().getTime()
    if now - lastClick > 100
    $("#message").show()
    lastClick = now

    View Slide

  41. Good Part:
    Strict comparisons

    View Slide

  42. Good Part:
    Strict comparisons
    == vs. ===

    View Slide

  43. Good Part:
    Strict comparisons
    "true" == true // true
    "true" === true // false
    "0" == false // true
    "0" == 0 // true
    0 === false // false
    "" == false // true

    View Slide

  44. Good Part:
    Strict comparisons
    "true" is true // false
    "true" is "true" // true
    "0" is false // false
    "0" is 0 // false
    0 is 0 // true
    "" is false // false

    View Slide

  45. Good Part:
    Runs anywhere

    View Slide

  46. Good Part:
    Runs anywhere
    JSLint compliant

    View Slide

  47. 10 Things I Love
    About CoffeeScript

    View Slide

  48. 1. Function Syntax

    View Slide

  49. 1. Function Syntax
    function greet (name) {
    return "Hello " + name;
    }

    View Slide

  50. 1. Function Syntax
    greet = (name) ->
    "Hello " + name

    View Slide

  51. 1. Function Syntax
    $("a").click(function(event) {
    $(this).addClass("busy");
    });

    View Slide

  52. 1. Function Syntax
    $("a").click (event) ->
    $(this).addClass "busy"

    View Slide

  53. 2. Significant Whitespace

    View Slide

  54. 2. Significant Whitespace
    if (url) {
    $.get(url, function(data) {
    return $("#result").html(data);
    });
    } else {
    $("#error").show();
    }

    View Slide

  55. 2. Significant Whitespace
    if url
    $.get url, (data) ->
    $("#result").html data
    else
    $("#error").show()

    View Slide

  56. 2. Significant Whitespace
    var readConfiguration = function(callback) {
    return path.exists(filename, function(err, exists) {
    if (exists) {
    return fs.readFile(filename, callback);
    } else {
    return callback(false);
    }
    });
    };

    View Slide

  57. 2. Significant Whitespace
    readConfiguration = (callback) ->
    path.exists filename, (err, exists) ->
    if exists
    fs.readFile filename, callback
    else
    callback false

    View Slide

  58. 3. Bare Objects

    View Slide

  59. 3. Bare Objects
    $(this).css({ top: "20px", left: "-20px" });

    View Slide

  60. 3. Bare Objects
    $(this).css top: "20px", left: "-20px"

    View Slide

  61. 3. Bare Objects
    $.ajax({
    url: path,
    timeout: 5,
    data: {
    from: "workspace"
    },
    dataType: "html",
    success: function(data) {
    return $("#result").html(data);
    }
    });

    View Slide

  62. 3. Bare Objects
    $.ajax
    url: path,
    timeout: 5,
    data:
    from: "workspace",
    dataType: "html",
    success: (data) ->
    $("#result").html data

    View Slide

  63. 3. Bare Objects
    person =
    name: "Sam"
    age: 27
    profession: "Programmer"

    View Slide

  64. 4. Everything’s an Expression

    View Slide

  65. 4. Everything’s an Expression
    switch keyCode
    when 38
    command = "previous"
    when 40
    command = "next"
    when 13
    command = "select"

    View Slide

  66. 4. Everything’s an Expression
    command = switch keyCode
    when 38 then "previous"
    when 40 then "next"
    when 13 then "select"

    View Slide

  67. 4. Everything’s an Expression
    getCommand = (keyCode) ->
    switch keyCode
    when 38 then "previous"
    when 40 then "next"
    when 13 then "select"

    View Slide

  68. 5. Comprehensions

    View Slide

  69. 5. Comprehensions
    names = []
    for person in people
    names.push capitalize person.name

    View Slide

  70. 5. Comprehensions
    names = for person in people
    capitalize person.name

    View Slide

  71. 5. Comprehensions
    ages = (person.age for person in people)

    View Slide

  72. 5. Comprehensions
    names = for person in people when age > 27
    capitalize person.name

    View Slide

  73. 5. Comprehensions
    var names, person;
    names = (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = people.length; _i < _len; _i++) {
    person = people[_i];
    if (age > 27) {
    _results.push(capitalize(person.name));
    }
    }
    return _results;
    })();

    View Slide

  74. 6. Classes & Inheritance

    View Slide

  75. 6. Classes & Inheritance
    class Photo
    constructor: (url) ->
    this.url = url
    createElement: ->
    $("").attr "src", this.url

    View Slide

  76. 6. Classes & Inheritance
    class Photo
    constructor: (url) ->
    this.url = url
    createElement: ->
    $("").attr "src", this.url

    View Slide

  77. 6. Classes & Inheritance
    class Photo
    constructor: (url) ->
    @url = url
    createElement: ->
    $("").attr "src", @url

    View Slide

  78. 6. Classes & Inheritance
    class Photo
    constructor: (@url) ->
    createElement: ->
    $("").attr "src", @url

    View Slide

  79. 6. Classes & Inheritance
    class Thumbnail extends Photo
    createElement: ->
    $el = super
    $el.height 100

    View Slide

  80. 6. Classes & Inheritance
    var Thumbnail;
    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;
    };
    Thumbnail = (function() {
    __extends(Thumbnail, Photo);
    function Thumbnail() {
    Thumbnail.__super__.constructor.apply(this, arguments);
    }
    Thumbnail.prototype.createElement = function() {
    var $el;
    $el = Thumbnail.__super__.createElement.apply(this, arguments);
    return $el.height(100);
    };
    return Thumbnail;
    })();

    View Slide

  81. 7. Bound Functions

    View Slide

  82. 7. Bound Functions
    class PersonView
    constructor: (@person, @el) ->
    request: ->
    $.get @person.url, (data) ->
    $(@el).html data

    View Slide

  83. 7. Bound Functions
    class PersonView
    constructor: (@person, @el) ->
    request: ->
    $.get @person.url, (data) ->
    $(@el).html data

    View Slide

  84. 7. Bound Functions
    function request () {
    $.get(this.person.url,
    (function(data) {
    $(this.el).html(data);
    }).bind(this)
    )
    }

    View Slide

  85. 7. Bound Functions
    class PersonView
    constructor: (@person, @el) ->
    request: ->
    $.get @person.url, (data) =>
    $(@el).html data

    View Slide

  86. 7. Bound Functions
    class PersonView
    constructor: (@person, @el) ->
    $(@el).bind "click", @showName
    showName: =>
    $(@el).html @person.name

    View Slide

  87. 8. Conditionals

    View Slide

  88. 8. Conditionals
    @request() if @isActive()
    return unless $("li").length

    View Slide

  89. 8. Conditionals
    result + 10 if result?

    View Slide

  90. 8. Conditionals
    @panel?.restore()

    View Slide

  91. 8. Conditionals
    @panel.url ?= window.location

    View Slide

  92. 9. Destructuring Assignment

    View Slide

  93. 9. Destructuring Assignment
    name = person.name

    View Slide

  94. 9. Destructuring Assignment
    name = person.name
    {name} = person

    View Slide

  95. 9. Destructuring Assignment
    name = person.name
    {name} = person
    {name, age} = person

    View Slide

  96. 9. Destructuring Assignment
    [first, last] = person.name.split " "

    View Slide

  97. 10. String Syntax

    View Slide

  98. 10. String Syntax
    greet = (name) ->
    "Hello #{name}"

    View Slide

  99. 10. String Syntax
    greet = (name) ->
    "Hello #{name.toUpperCase()}"

    View Slide

  100. 10. String Syntax
    render = (person) ->
    """

    #{person.name}
    #{person.profession}

    """

    View Slide

  101. How To
    Use It

    View Slide

  102. View Slide

  103. View Slide

  104. Command Line
    $ npm install -g coffee-script

    View Slide

  105. Command Line
    $ coffee -c hello.coffee
    $ cat hello.js
    (function() {
    alert("hello");
    }).call(this);

    View Slide

  106. Command Line
    $ coffee -cw hello.coffee

    View Slide

  107. Rails 3.1
    Sprockets
    https://github.com/sstephenson/sprockets

    View Slide

  108. Node.js
    Stitch
    https://github.com/sstephenson/stitch

    View Slide

  109. Thank
    You
    @sstephenson

    View Slide

  110. http://coffeescript.org/

    View Slide