@rob_rich
#confoo

A taste of ES6:
the language and the tools

by Rob Richardson

@rob_rich

http://robrich.org/

About Me

Rob Richardson is a software craftsman building web properties in ASP.NET and Node, Angular and React. He's a frequent speaker at conferences, user groups, and community events, and a diligent teacher and student of high quality software development. You can find this and other talks on his blog at https://robrich.org/presentations and follow him on twitter at @rob_rich.

Source: Google Maps

Source: flickr.com/photos/miguelfolch/3228781745

ES6

So which is it?

JavaScript Harmony

EcmaScript 6

EcmaScript 2015

ES6


... they're the same thing

EcmaScript 6

... in the browser


The server-side ES6 story is interesting too,
but we'll focus on the browser story

EcmaScript 6

Two main groups of new things:

  • New Features
  • New Syntax:
      sugar over existing features

Can I use it today?

Yes but ...

Browser support:
https://kangax.github.io/compat-table/es6/

 

spoiler: Browsers are lagging behind but getting close,
but you can "transpile" to ES5 and use it in browsers today

What is Transpiling?

Transpiling is a specific term for taking source code written in one language and transforming into another language that has a similar level of abstraction.

Source: https://www.stevefenton.co.uk/2012/11/compiling-vs-transpiling/

The Tools

Groups of Tools

  • Polyfills: add missing methods
  • Transpiler: convert ES6 to similar ES5
  • Bundler: polyfill module loading

Polyfills

Can I polyfill the feature?

HTML5 examples:

Yes: html5shiv adds Array methods and additional tags

No: Can't polyfill canvas tag

Transpilers

Using Babel

  1. Visit babeljs.io/docs/setup/
  2. Choose your host
  3. Include the provided code

Using Babel

  1. Visit babeljs.io/repl/
  2. Type stuff

Bundlers

Using Webpack

npm install -g webpack
webpack main.js bundle.js

Then reference bundle.js from your html

Using Webpack

webpack.config.js:

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    }
};

Using Webpack with Babel

webpack.config.js:

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    module: {
        use: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: ['babel-loader']
            }
        ]
    }
};

.babelrc:

...

Using Webpack with Babel

webpack.config.js:

...

.babelrc:

{
  presets: ['es2015', 'es2016, 'es2017]
}

Then run these from the command line

npm install --save-dev webpack babel-core babel-loader
npm install --save-dev babel-preset-es2015 babel-preset-es2016 babel-preset-es2017
webpack

Babel Presets

TC39 categories

  • es2015: ES6 features
  • es2016: ES7 features
  • es2017: ES8 features
  • stage-4: Finished: will go to next yearly release.
  • stage-3: Complete spec, initial browser implementations.
  • stage-2: Draft
  • stage-1: Proposal
  • stage-0: Strawman: an idea

Source: babeljs.io/docs/plugins/

Can I use it today?

Yes.

Use WebPack and Babel
to transpile an ES6/7/8 app into an ES5 file.

The Language

Cool Syntax

Sprinkle in sparingly

Don't use it just to use it

Use it when it adds clarity
and simplicity to your code

Code for legibility

Code like the person maintaining your code is a homicidal maniac that knows where you live.

- Jeremy Clark

Variable scoping

let and const

  • scoped to curly braces, not to the function

Variable scoping

ES5: var

function hello() {
    console.log(message);
    // undefined
    if (true) {
        var message = 'hello world';
        console.log(message);
        // 'hello world'
    }
    console.log(message);
    // 'hello world'
}

ES6: let, const

function hello() {
    console.log(message);
    // exception
    if (true) {
        let message = 'hello world';
        console.log(message);
        // 'hello world'
    }
    console.log(message);
    // exception
}

"fat arrow" functions

=>

  • binds "this" at definition
  • always anonymous
  • single line implicit last line return
  • function is still best for heavy lifting

"fat arrow" functions

ES5: function

var array = [1,2,3];
array.map(function (a) {
  return a * 2;
});

ES6: =>

var array = [1,2,3];
array.map(a => a * 2);

"fat arrow" functions

Build it up

function (a) { return a * 2; }
(a) => { return a * 2; }
a => { return a * 2; }
a => a * 2;

All of these are valid ES6 syntax

Classes

  • Syntactic sugar over prototype chain
  • It makes it feel like C# / Java
  • ... it still works the same

Classes

ES5: constructor function

function Person(name) {
    this.name = name;
}
Person.prototype.speak = function () {
    console.log('hello '+this.name);
};

ES6: class

class Person {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log('hello '+this.name);
    }
}

Polyfill Promise

Asynchronous resolve

  • proxy for a later result
  • alternate style to callbacks
  • religious war: some find it more confusing

Polyfill Promise

Asynchronous resolve

ES5: callback

function doWork(cb) {
    cb(null, 'results');
}

doWork(function (err, results) {
    if (err) {
        // handle error
    }
    // handle success
});

ES6: promise

function doWork() {
    return new Promise(function (success, fail) {
        success('result');
    });
}

doWork().then(function (result) {
    // handle success
}).catch(err) {
    // handle error
});

Modules

  • CommonJS module resolution
  • resolves dependencies synchronously
  • can reference only portions of the dependency

Modules

ES5:


ES6: export and import

// -------- lib.js --------
export function square(x) {
    return x * x;
}

// -------- main.js --------
import * as lib from './lib';
lib.square(4); // 16

Modules

Node:

// -------- lib.js --------
function square(x) {
    return x * x;
};

module.exports = {
  square: square
};

// -------- main.js --------
var lib = require('./lib');
lib.square(4); // 16

ES6: export and import

// -------- lib.js --------
export function square(x) {
    return x * x;
}

// -------- main.js --------
import * as lib from './lib';
lib.square(4); // 16

Modules

Node:

// -------- lib.js --------
function square(x) {
    return x * x;
}

module.exports = {
  default: square
};

// -------- main.js --------
var lib = require('./lib').default;
lib(4); // 16

ES6: export and import

// -------- lib.js --------
export default function (x) {
    return x * x;
}

// -------- main.js --------
import lib from './lib';
lib(4); // 16

String Templates

  • Use variables inline
  • Multi-line strings
  • Automatically encodes

String Templates

ES5: add strings

var a = 5;
var b = 10;
var msg = "Fifteen is " + (a + b) + " and\n";
message += "not " + (2 * a + b) + ".");
console.log(msg);
// "Fifteen is 15 and
// not 20."

ES6: string templates

var a = 5;
var b = 10;
var msg = `Fifteen is ${a + b} and
not ${2 * a + b}.`;
console.log(msg);
// "Fifteen is 15 and
// not 20."

Building objects

  • Syntactic sugar for declaring variables more easily

Building objects

ES5:

var x = 3;
var y = 7;
var c = {
    x: x,
    y: y
};

ES6:

var x = 3;
var y = 7;
var c = { x, y };

Building objects

ES5:

var x = 3;
var y = 7;
var c = {
    x: x,
    y: y,
    z: 9
};

ES6:

var x = 3;
var y = 7;
var c = {
    x,
    y,
    z: 9
};

Dereferencing objects

ES5:

var c = { x: 3, y: 7 };

var x = c.x;
var y = c.y;
console.log(x); // 3

ES6:

var c = { x: 3, y: 7 };

let { x, y } = c;
console.log(x); // 3

Dereferencing objects

ES5:


ES6:

// -------- lib.js --------
export function square(x) {
    return x * x;
}
export function double(x) {
    return x * 2;
}

// -------- main.js --------
import { square, double } from './lib';
square(4); // 16
double(4); // 8

Rest parameters

  • Get the rest of the arguments passed as an array
  • Must be the last argument
  • Much better than "arguments" pseudo-array

Rest parameters

ES5:

function (a, b) {
    var theRest = Array.prototype.slice.call(arguments);
    theRest.shift(); // a
    theRest.shift(); // b

    theRest.forEach(function () {
        // ...
    });
}

ES6:

function(a, b, ...theRest) {
    theRest.forEach(function () {
        // ...
    });
}

Spread operator

  • Turn array into a list of parameters
  • Like apply() but doesn't change "this"

Spread operator

Pass an array like a series of arguments

ES5:

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);

ES6:

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);

Spread operator

A more powerful array literal

ES5:

var parts = ['shoulders', 'knees'];
// duplicate array
var lyrics = parts.slice();
lyrics.unshift('head');
lyrics.push('and');
lyrics.push('toes');
// ["head", "shoulders", "knees", "and", "toes"]

ES6:

var parts = ['shoulders', 'knees'];
var lyrics = [
  'head',
  ...parts,
  'and',
  'toes'
];
// ["head", "shoulders", "knees", "and", "toes"]

Rest and Spread operators

A more powerful array literal

Rest:

function(a, b, ...theRest) {
    theRest.forEach(function () {
        // ...
    });
}

Spread:

var args = [0, 1, 2];
myFunction(...args);

Cool Syntax

Sprinkle in sparingly to add legibility

Syntax over existing features

Tools

ES6 -> ES5: babeljs.io

Polyfill import and export: webpack.github.io

Polyfill other things as needed

Yes!

You can use ES6 today.