Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Sam Stephenson 37signals

Slide 3

Slide 3 text

Better JavaScript with CoffeeScript

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

A Brief Personal History

Slide 6

Slide 6 text

2004

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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); }

Slide 9

Slide 9 text

. prototype .

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

2010

Slide 14

Slide 14 text

We’re Stuck With JavaScript

Slide 15

Slide 15 text

Compile to JavaScript

Slide 16

Slide 16 text

Google Web Toolkit

Slide 17

Slide 17 text

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); } }

Slide 18

Slide 18 text

Com_example_gwt_helloworld.html

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

Pyjamas

Slide 22

Slide 22 text

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()

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Objective-J

Slide 27

Slide 27 text

@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

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

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.

Slide 30

Slide 30 text

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.

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Good Part: Private by default

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Good Part: No more var

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Good Part: Strict comparisons

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Good Part: Runs anywhere

Slide 46

Slide 46 text

Good Part: Runs anywhere JSLint compliant

Slide 47

Slide 47 text

10 Things I Love About CoffeeScript

Slide 48

Slide 48 text

1. Function Syntax

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

2. Significant Whitespace

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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); } }); };

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

3. Bare Objects

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

4. Everything’s an Expression

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

5. Comprehensions

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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; })();

Slide 74

Slide 74 text

6. Classes & Inheritance

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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; })();

Slide 81

Slide 81 text

7. Bound Functions

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

8. Conditionals

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

8. Conditionals result + 10 if result?

Slide 90

Slide 90 text

8. Conditionals @panel?.restore()

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

9. Destructuring Assignment

Slide 93

Slide 93 text

9. Destructuring Assignment name = person.name

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

10. String Syntax

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

10. String Syntax render = (person) -> """
#{person.name} #{person.profession}
"""

Slide 101

Slide 101 text

How To Use It

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

Command Line $ npm install -g coffee-script

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

Command Line $ coffee -cw hello.coffee

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

Thank You @sstephenson

Slide 110

Slide 110 text

http://coffeescript.org/