ECMAscript 6

The Great Parts!

Created by Curtis Schlak for the October meeting of the HoustonJS group

Creative Commons License

You can follow along...

http://curtis.schlak.com/learnerjs-201410

We will see...

Modules

Loading scripts.
Loading dependencies.

It started with...


<script src="js/MozCompat.js"></script>
<script src="js/themes.js"></script>
<script src="js/flash.js"></script>
<script src="js/Navigation.js"></script>
<script src="js/GTracking.js"></script>
<script src="js/Home.js"></script>
<script src="js/ieminwidth.js"></script>
<script src="js/slideshow.js"></script>
<script src="js/HomeTail.js"></script>
            

Then, YUI2 moved it forward


<script src="yuiloader-beta-min.js"></script>
<script>
  loader = new YAHOO.util.YUILoader();
  loader.require('colorpicker', 'treeview');
  loader.insert(function () {
    new YAHOO.widget.ColorPicker('picker-div');
    new YAHOO.widget.TreeView('tree-div');
  });
</script>
            

"Standards" emerged

managing dependencies between modules

  • CommonJS
  • Asynchronous Module Definition (AMD)
  • Dojo modules
  • YUI3 modules

TC39 said, "meh"

Importing

import theDefault from 'module';
import * as aNamespace from 'module';
import { namedExport } from 'module';
import { namedExport as aliased } from 'module';

Exporting

export var v;
export default function f () {};
export default function () {};
export default 42;
export { namedExport };
export { namedExport as aliased };
export { namedExport } from 'anotherModule';

Use the module,now.

Classes

Sugary sweet goodness for syntax

What it used to be like

function Parent (value) { this.parentValue = value; } Parent.prototype.toString = function () { return 'PARENT: ' + this.parentValue; }; function Child (childValue, parentValue) { Parent.call(this, parentValue); this.childValue = childValue; } Child.prototype = new Parent(); Child.prototype.toString = function () { return 'CHILD: ' + this.childValue + ', ' + Parent.prototype.toString.call(this); }; var child = new Child('Kate H', 'Goldie H') console.log(String(child));

Welcome class and extend!

class Parent { constructor (value) { this.parentValue = value; } toString() { return 'PARENT: ' + this.parentValue; } } class Child extends Parent { constructor(childValue, parentValue) { super(parentValue); this.childValue = childValue; } toString() { return 'CHILD: ' + this.childValue + ', ' + super.toString(); } } var child = new Child('George W', 'George HW'); console.log(String(child));

It works even deeper...

class Parent { constructor (value) { this.parentValue = value; } toString() { return 'PARENT: ' + this.parentValue; } } class Child extends Parent { constructor(childValue, parentValue) { super(parentValue); this.childValue = childValue; } toString() { return 'CHILD: ' + this.childValue + ', ' + super.toString(); } } class GrandChild extends Child { constructor(grandchildValue, childValue, parentValue) { super(childValue, parentValue); this.grandchildValue = grandchildValue; } toString() { return 'GRANDCHILD: ' + this.grandchildValue + ', ' + super.toString(); } } console.log(String(new GrandChild('Margaux', 'Mary', 'Ernest')));

Warning: still prototypal

class Parent { constructor (value) { this.value = value; } toString() { return 'PARENT: ' + this.value; } } class Child extends Parent { constructor(childValue, parentValue) { super(parentValue); this.value = childValue; } toString() { return 'CHILD: ' + this.value + ', ' + super.toString(); } } var child = new Child('Mira S', 'Paul S'); console.log(String(child));

Lambdas

We call them
arrow functions

A lot like functions

function fn (n) { return 1 + n; } let lambda = n => 1 + n; console.log(fn(3), lambda(3));

So, what's the
difference?

Besides being all easier to type and stuff?

this. Literally.

let thisSlide = document.getElementById('this-as-self'); thisSlide.addEventListener('click', function clicky () { // SAVE HERE! var self = this; thisSlide.removeEventListener('click', clicky); setTimeout(function () { // TO USE HERE! console.log('self === this:', self === this); console.log('self:', self); console.log('this:', this); }, 0); });

Arrow functions have no this.

let thisSlide = document.getElementById('lambda-has-no-this'); thisSlide.addEventListener('click', function clicky () { thisSlide.removeEventListener('click', clicky); // The "this" in this lambda is the "this" of the // declaring context! setTimeout(() => console.log(this), 0); });

Proxies

Letting others answer questions.

a person an object authorized to act
on behalf of another

Example: Log all gets

let target = function targetFn () {}; target.firstName = 'Curtis'; target.age = function () { return Number.POSITIVE_INFINITY; }; let handler = { get(target, name) { console.log('calling', name, 'on', target.name); return target[name]; }, apply(t) { console.log('Invoking the object!!!'); return t; } }; let p = new Proxy(target, handler); p(p.firstName, p.age());

Things to intercept

  • get
  • set
  • deleteProperty
  • enumerate
  • ownKeys
  • has
  • defineProperty
  • getOwnPropertyDescriptor
  • getPrototypeOf
  • setPrototypeOf
  • isExtensible
  • preventExtensions
  • apply
  • construct

De
struc
turing

Bind to object properties

function kindOfMulti () { return { one: 1, two: 'zwei', three: 3.0 }; } let { one: o, two: t, three: th } = kindOfMulti(); console.log(o, t, th);

Bind to arrays

function kindOfMulti () { return [ 'uno', 2.0, 3 ]; } // ignore some arguments let [ ,, th ] = kindOfMulti(); console.log(th);

Also works for parameters

function destructure ({ name: n, age: a}) { console.log('I am', n, 'and I am', a, 'years old!'); } var person = { name: 'Virginia', age: 8 }; destructure(person);

Mix and match

function destructure () { return [ 0, { first: 1, second: 2, ignored: 'always' }, [ 3, 4, 5 ] ] } let [a, { first: b, second: c }, [ d, e, f ]] = destructure(); console.log(a, b, c, d, e, f)

Restructuring?

That's kind of a joke. The arguments variable has always been a hacky way of working with variable arguments. It's not even a proper array.

Now, we have the ... operator to bind remaining arguments!

The ...rest of the story

function restParameter (i, j, ...rest) { console.log(i + j); console.log(Array.isArray(rest), rest); } restParameter(3, .14, 1, 2, 4, 8, 16);

Generate oars

In python

def firstn(n): num = 0 while num < n: yield num num += 1

In C#

class GeneratorDude { public IEnumerable<int> FirstN(int n) { int i = 0; while (i < n) { yield return i; i += 1; } } }

In ECMAscript

function* firstn(n) { let i = 0; while (i < n) { yield i; i += 1; } } for (var i of firstn(5)) { console.log(i); }

Generators using generators

function* beatles() { let names = [ 'John', 'Paul', 'George', 'Ringo' ]; for (let name of names) { yield name; } } function* dudes() { let names = [ 'Jackie', 'Tito', 'Jermaine', 'Maron', 'Michael' ]; for (let name of names) { yield name; } yield* beatles(); } for (var name of dudes()) { console.log(name); }

Templates

Phooey on jade!

Supports multiple lines

let multiline = `line one line two line three`; console.log(multiline);

Interpolation, too!

function replace(replacement, another) { return `static line here's a ${replacement} and ${another} and 2 + 3 = ${2 + 3}!`; } console.log(replace('monkey', 'cheese'));

Lovely!

I don't know what this is

function replace(str, ...parts) { console.log(str, parts); } let one = 1; let two = 2; replace`one ${one} two ${two}`

Symbols

Secret things...

A symbol is a unique and immutable data type. You can use it as an identifier for object properties.

 

LiSP and Ruby programmers will get this.

Without symbols

export class Person { constructor(name) { this._name = name; } get name() { return this._name; } } let person = new Person('Talachia'); console.log(person.name); console.log(Object.keys(person));

With symbols

let nameProp = Symbol('name'); export class Person { constructor(name) { this[nameProp] = name; } get name() { return this[nameProp]; } } let person = new Person('Megan'); console.log(person.name); console.log(Object.keys(person));