Modern JavaScript

ECMAScript 3/5

ES5

  • Array methods
  • Object methods
  • (function) bind
  • JSON (built-in)

ES6 / ES2015

Like before

both good parts and bad parts

variable assignment

  • block scoping (let)

  • non-reassignment (const)

let

// "block scope"
// in js (lol)

{
  var a = 5;
}

console.log(a);

// >> 5

let

// "block scope"
// in ES2015 (yay)

{
  let a = 5;
}

console.log(a);

// >> ReferenceError:
// >> a is not defined

let

// old style var
if (true) {
  var a = 5;
}

console.log(a)

// >> 5

let

// new let block scope
if (true) {
  let b = 5;
}

console.log(b)

// >> ReferenceError:
// >> b is not defined...

let

// old style var
for (var i = 0; i < 10; i++) {...}

console.log(i);
// >> 10

let

// new let block scope
for (let j = 0; j < 10; j++) {...}

console.log(j);
// >> ReferenceError: j is not defined..

const

// old var style
var a = 5;
a = 6;

console.log(a)
// >> 6;

const

// new const assignment
const a = 5;
a = 6;

console.log(a)
// >> 5;

const

// old var style
var b = 5;
var b = 6;

// Everything is good here (?)

const

// new const assignment (no reassignment)
const b = 5;
const b = 6;

// >> TypeError:
// >> Identifier 'b' has already been declared..

const

// no immutability beyond primitives..
const a = {};
a.name = 'John';

console.log(a);
// >> { name: 'John' }

Template literals

Template literals

old ugly style



let greeting = 'Good morning ' + firstName + ' ' + lastName; 

Template literals

new nice style!

Note: these are back-ticks - not quotes



let greeting = `Good morning ${firstName} ${lastName}`; 

Template literals

any js expression


let names = ['John', 'Frank', 'Bob', 'Alice'];
let greeting = `Good morning ${names.join(' ')}`;

// >> Good morning John Frank Bob Alice

Multiline strings in js..

Template literals

old multiline style

let title = 'My awesome site';
let markup =
        '<!doctype html>\n' +
        '<html>\n' +
        '<head>\n' +
        '    <meta charset="UTF-8">\n' +
        '    <title>' + title + '</title>\n' +
        '</head>\n' +
        '<body>\n' +
        '</body>\n' +
        '</html>\n';

Template literals

old multiline style

let title = 'My awesome site';
let markup = '\
        <!doctype html>\n\
        <html>\n\
        <head>\n\
            <meta charset="UTF-8">\n\
            <title>' + title + '</title>\n\
        </head>\n\
        <body>\n\
        </body>\n\
        </html>';

Template literals

new multiline style

let title = 'My awesome site';
let markup = `
        <!doctype html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>${title}</title>
        </head>
        <body>
        </body>
        </html>
`;

Arrow functions

Arrow functions



let square = function(a) { return a * a };
let square = (a) => { return a * a };
let square = (a) => a * a;
let square = a => a * a;

syntax sugar for anonymous functions

Arrow functions



let numbers = [1, 2, 3];
let squaredNumbers = numbers.map(a => a * a);
// >> [1, 4, 9]

syntax sugar for anonymous functions

this

this, self, that...

function Dog(name) {
  this.name = name;

  this.barkAsync = function() {
    let self = this;

    setTimeout(function() {
      setTimeout(function() {
        console.log(`${self.name} barks!`);
      }, 1000);
    }, 1000);
  };
}

let Fido = new Dog('Fido');
Fido.barkAsync();

bind (ES5)

function Dog(name) {
  this.name = name;

  this.barkAsync = function() {
    setTimeout(function() {
      setTimeout(function() {
        console.log(`${this.name} barks!`);
      }.bind(this), 1000);
    }.bind(this), 1000);
  };
}

let Fido = new Dog('Fido');
Fido.barkAsync();

Arrow functions



let myFunc = () => {...}
let myFunc = function() {...}.bind(this)

implicit bind to the outer 'this'

Arrow functions

function Dog(name) {
  this.name = name;

  this.barkAsync = () => {
    setTimeout(() => {
      setTimeout(() => {
        console.log(`${this.name} barks!`);
      }, 1000);
    }, 1000);
  };
}

let Fido = new Dog('Fido');
Fido.barkAsync();

Destructuring

Destructuring

Avoid intermediate variables + nicer syntax

Destructuring

Objects (old style)

let person = {
  name: 'John Doe',
  age: 30
};

let name = person.name;
let age = person.age;
// name = 'John Doe', age = 30

Destructuring

Objects (new style)

let person = {
  name: 'John Doe',
  age: 30
};

let { name, age } = person;
// name = 'John Doe', age = 30

Destructuring

Objects (return multiple)

function createConfig() {
  return {
    host: 'localhost',
    port: 3000
  };
}

let { host, port } = createConfig();
// host = 'localhost', port = 3000

Destructuring

Arrays (old style)

let numbers = [10, 20];

let a = numbers[0];
let b = numbers[1];
// a = 10, b = 20

Destructuring

Arrays (new style)

let numbers = [10, 20];

let [a, b] = numbers;
// a = 10, b = 20

Destructuring

Arrays (new style)

let numbers = [10, 20, 30];

let [a,,c] = numbers;
// a = 10, c = 30

Destructuring

Arrays (return multiple)

function createSomething() {
  return [10, 20];
}

let [a, b] = createSomething();
// a = 10, b = 20;

Destructuring

Nested mix (arbitrarily deep)

let obj = {
    a: [{
        foo: 123,
        bar: 'abc'
    }, {}],
    b: true
};

let { a: [{foo: f}] } = obj;

// f = 123

Rest and Spread

...

Rest parameter

function concat(separator) {
  var params = Array.prototype.slice.call(arguments);
  return params.join(separator);
}

concat('_', 'a', 'b', 'c', 'd');
// >> 'a_b_c_d'

the old way

Rest parameter

using ...

function concat(separator, ...params) {
  return params.join(separator);
}

concat('_', 'a', 'b', 'c', 'd');
// 'a_b_c_d'

Spread operator


let numbers = [1, 2, 3, 4, 5];
let [head, ...tail] = numbers;
// head = 1;
// tail = [2, 3, 4, 5];

for destructuring

Spread operator


let odds = [1, 3];
let evens = [2, 4];
let numbers = [...odds, ...evens];
// numbers = [1, 3, 2, 4]

for merging arrays

Iteration

Iteration

the ES3 way

let person = {
  name: 'John',
  age: 30
};

for (let prop in person) {
  if (person.hasOwnProperty(prop)) {
    console.log(prop + ': ' + person[prop]);
  }
};

// name: John
// age: 30

Iteration

the ES5 way

let person = {
  name: 'John',
  age: 30
};

Object.keys(person).forEach(function(prop) {
  console.log(prop + ': ' + person[prop]);
})

// name: John
// age: 30

Iteration

the ES6 way

let person = {
  name: 'John',
  age: 30
};

for (let prop of person) {
  console.log(prop + ': ' + person[prop]);
}

// name: John
// age: 30

Default values

Default values

old way

function setup(host, port, done) {
  host = host || 'localhost';
  port = port || 3000;
  done = done || function() {};

  ....
}

Default values

new way

function setup(
  host = 'localhost', 
  port = 3000,
  done = function() {}
) {

  ....
}

Options object

function setup(options) {
  var host = options.host || 'localhost';
  var port = options.port || 3000;
  var done = options.done || function() {}

  ...
}

Options object

function setup(options) {
  let {
    host = 'localhost',
    port = 3000,
    done = function() {}
  } = options;

  ...
}

Named parameters

function setup({ host, port, done }) {
  host = host || 'localhost';
  port = port || 3000;
  done = done || function() {};

  ....
}

Named parameters

with defaults

function setup({
  port = 3000,
  host = 'localhost',
  done = () => {}
}) {

  ....
}

Object shorthands

less writing..

Object shorthands

let name = 'John';
let age = 30;

let person = {
  name: name,
  age: age
};

old way

Object shorthands

let name = 'John';
let age = 30;

let person = {
  name,
  age
};

new way

Object shorthands


let person = {
  name: 'John',
  greet: function() {
    console.log(`${this.name}: hello`)
  }
};

old way

Object shorthands


let person = {
  name: 'John',
  greet() {
    console.log(`${this.name}: hello`)
  }
};

new way

Some more good stuff

  • Generators (yielding)

  • Modules (import)

  • Classes (...)

  • Map / WeakMap

  • Set / WeakSet

  • Array methods

  • Object methods

Check out

http://es6katas.org/
http://exploringjs.com/es6/

Beyond ES2015

Even further

ES7 / ES2016

  • async / await

  • observables

  • decorators

Transpilation

Before


let numbers = [1, 2, 3, 4];
let [head, ...tail] = numbers;
let add = (x, y) => x + y;

After

var numbers = [1, 2, 3, 4];
var head = numbers[0];
var tail = numbers.slice(1);

var add = function add(x, y) {
  return x + y;
};

Try it out

Usage example


# install babel globally
> npm install -g babel

# transpile from ES6+ to ES5
> babel script.js --out-file script-compiled.js

Start using it now!

(Everywhere)

http://babeljs.io

Questions?

Thanks!

@eiriklv / vullum.io

Modern JavaScript - ES2015 and beyond (Ciber)

By Eirik Langholm Vullum

Modern JavaScript - ES2015 and beyond (Ciber)

What the new JavaScript specs bring to the table and how to start using them today

  • 2,690