[ JS | DOM ].next()

Alex Russell
LondonJS
Oct 17, 2011

http://www.flickr.com/photos/ttrueman/6201316684




http://www.flickr.com/photos/chrischabot/5714334543

The Near Future

  • try { ... } catch (e) { ... } optimization
  • Incremental GC
  • Proxies
Today's Toolkits Are The TODO List For Tomorrow's Platform

Personal Goals For ES.next

http://www.flickr.com/photos/futileboy/4855889430

Defaults & Destructuring

function el(tagName="div", attrs={}, innerHTML="") {
  // ...
}
document.body.appendChild( el("table", { id: "data" }) );
function f() { return [1, 2] }
var a, b;
[a, b] = f();
{ foo: a, bar: b } = f();

for ( let [name, value] in obj )
    console.log("Name:", name, "Value:", value);

Spread & The Death of .apply()

function handleMany(required=0, ...optional) {
  // It's a real Array!
  optional.forEach(console.log);
}
var items = [ "ennie", "meenie", "minney", "moe" ];

// Old.
obj.method.apply(obj, items);

// New! Shiny!
obj.method(...items);

Block Scope

// let is the new var!
function() {
  "use strict";

  let outer = "thinger";

  { // This is a block
    let inner = "other thinger!";
    let const scopedConst = { prop: 15 };
  }

  console.log(inner); // undefined
}

Short Functions: Option 1 -- Block Lambdas

let identity = {|x| x};

// Paren-free
let b = a.map {|e| e * e}

node.addEventListener("click", {|e| console.log(e.target); });

function find_first_odd(a) {
  a.forEach { |e, i|
              if (e & 1) return i; }        // return from find_first_odd
  return -1;
}

Short Functions: Option 2 -- Arrow functions

let identity = (x) -> x;

// Paren-free
let b = a.map (e) -> { e * e }

node.addEventListener("click", (e) -> { console.log(e.target); });

function find_first_odd(a) {
  var r = -1;
  a.some((e, i) -> {
    if (e & 1) r = i;
    return r !== -1;
  }};
  return r;
}

Binary Data

const Point2D = new StructType({ x: uint32, y: uint32 });
const Color = new StructType({ r: uint8, g: uint8, b: uint8 });
const Pixel = new StructType({ point: Point2D, color: Color });
 
const Triangle = new ArrayType(Pixel, 3);
 
let t = new Triangle([{ point: { x:  0, y: 0 }, color: { r: 255, g: 255, b: 255 } },
                      { point: { x:  5, y: 5 }, color: { r: 128, g: 0,   b: 0   } },
                      { point: { x: 10, y: 0 }, color: { r: 0,   g: 0,   b: 128 } }]);

Classes Today

function Comment(text) {
  HTMLElement.call(this); // Makes this an Element
  ...
}

Comment.prototype = Object.create(HTMLElement.prototype);
Comment.prototype.constructor = Comment;
Comment.prototype.buildUI = function() { ... };

HTMLElement.register('x-comment', Comment);

Classes Today (For Real)

// Closure
goog.inherits(HTMLElement, Comment);

// Prototype
Comment = Class.create(HTMLElement, ... );

// MooTools
Comment = new Class({ extends: HTMLElement, ... });

// YUI
Comment = function () { Comment.superclass.constructor.call(this); }; 
YAHOO.lang.extend(Comment, HTMLElement);

// Dojo
dojo.define("Comment", [ HTMLElement ], ...);

// jQuery UI
$.widget( "comment", { ... });

ES.next Classes

class Comment extends HTMLElement {

  constructor(attrs = {}) {
    super(attrs);
    this.textContent = attrs.text || lorem;
    this.shadow = new ShadowRoot(this);
    this.buildUI();
  }

  buildUI() { ... }
}

HTMLElement.register('x-comment', Comment);

JavaScript Modularity?

goog.provide('goog.ui.tree.TreeControl');

goog.require('goog.events.EventType');
goog.require('goog.events.FocusHandler');
goog.require('goog.events.KeyHandler');
goog.require('goog.ui.tree.BaseNode');
goog.require('goog.ui.tree.TreeNode');
goog.require('goog.ui.tree.TypeAhead');

More tower of Babel

define("dijit/Tree",
  ["dojo",
   "dijit",
   "text!dijit/templates/TreeNode.html",
   "text!dijit/templates/Tree.html",
   "dijit/_Widget",
   "dijit/_Container",
   "dijit/_Contained"],
    function(dojo, dijit) {
      dojo.declare("dijit.Tree", ... );
      return dijit.Tree;
    });

ES.next Modules

module widgets {
  module events from 'goog/events.js';
  import {EventType, FocusHandler, KeyHandler} from events;
  import * from 'goog/widget.js';

  export let collection = [];
 
  export class DropDownButton extends Widget {
    constructor(attributes) {
      super(attributes);
      this.buildUI();
      // ...
    }
  }
}

Traceur


          
http://code.google.com/p/traceur-compiler/wiki/AddingTransformationPasses

Hacks-as-Platform

Coping Strategy Challenges
Progressive Enchancement Duplication, Complexity
Low-level Frameworks
(jQuery, Prototype, underscore)
Duplication, Performance
Widget Frameworks Duplication, Semantics, Searchability, Interop, Performance
Compilers
(GWT, CoffeeScript, Dart)
Dupliation, Complexity, Semantics, Searchability, Interop
The language isn’t the problem,
the platform is.

Components Today

<script src="http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js">
</script>
<script type="text/javascript">
YUI().use('calendar', 'datatype-date',  function(Y) {
    var calendar = new Y.Calendar({
      contentBox: "#mycalendar",
      width:'340px',
      showPrevMonth: true,
      showNextMonth: true,
      date: new Date(2011, 07, 01)}).render();
});
</script>

Components Today

<script 
 src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js">
</script>
<script>
dojo.require("dijit.dijit");
dojo.require("dijit.Calendar");

dojo.ready(function() {
    var c = new dijit.Calendar({
        value: new Date(),
        isDisabledDate: function(d) {
          // ...
        }
    });
    document.body.appendChild(c.domNode);
});
</script>

Declarative Components Today

<script 
  src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js"
  djConfig="parseOnLoad: true">
</script>
<script type="text/javascript">
    dojo.require("dijit.dijit"); // loads the optimized dijit layer
    dojo.require("dijit.Calendar");
</script>
<div dojoType="dijit.Calendar"
        value="2009-08-07"
        isDisabledDate="dojo.date.locale.isWeekend"
        onChange="...">
</div>

http://www.flickr.com/photos/lodefink/891416169

Web Components

function Comment(text) {
  HTMLElement.call(this); // Makes this an Element
  this.textContent = text || '...';
  this.buildUI();
}

Comment.prototype = Object.create(HTMLElement.prototype);
Comment.prototype.constructor = Comment;
Comment.prototype.buildUI = function() { ... };

HTMLElement.register('x-comment', Comment);
var c = new Comment("Howdy, pardner!");
document.body.appendChild(c);
<x-comment>...</x-comment>

Shadow DOM

function Comment(text) {
  HTMLElement.call(this); // Makes this an Element
  this.textContent = text || '...';
  this.shadow = new ShadowRoot(this);
  this.buildUI();
}

Comment.prototype = Object.create(HTMLElement.prototype);
Comment.prototype.constructor = Comment;
Comment.prototype.buildUI = function() { ... };

HTMLElement.register('x-comment', Comment);
<template id="commentTemplate">
  <div class="holder">
    <style scoped>
      img     { ... }
      .text   { ... }
      .holder { ... }
    </style>
    <img class="avatar" alt="avatar">
    <div class="text">
      <content></content>
    </div>
  </div>
</template>

Demo!

What About DOM?

http://www.dartlang.org/articles/improving-the-dom/

Et tu, Brute?

DOM.next for JS

import * from dom.next;

let d = document;

d.ready((e) -> {
  d.query("#content").elements.push(
    new HTMLDiv({ ... })
  );

  d.query("#nav").on.click.push((e) -> {
    e.target.rects.then((r) -> {
      console.log(r.contentWidth.px,
                  r.borderWidth.em,
                  r.paddingWidth.pct);
    });
  })
});

DOM.next Design Principles

http://www.flickr.com/photos/mikechen-metalman/4394618656
I don't have a crystal ball, but I do have the ability to look at how we're evolving the platform, and what I can say without reservation is that we need more experiments like this, not less. We need more "proprietary" things shipping sooner so we can try them out, and we need more ways for the *process* of progress to continue. But that depends on you. Will you support us as we experiment, or just loathe the fact that it's not ideal yet?

Thank you!

Questions?

@slightlylate

slightlyoff@chromium.org