JavaScript ES2015

@jniechcial

@nekath

What is ES2015 (aka ES6)?

New specification for JavaScript that introduces huge amount of great features that were impossible to either get or prototype polyfill 

Arrow functions, classes, interpolation, iterators, and more...

Is it supported already?

Only partially. So how can we use it safely?

Babel - the cure for incompatibilities

Babel is a tool to transform ES2015 to ES5 (fully supported)

How Babel works - quick insight

Babel is... transforming your code

Parser

Creates

Abstract Syntax Tree

Transformer

Manipulates

Abstract Syntax Tree

Generator

Generate JS from

Abstract Syntax Tree

ES2015 setup in Rails

Sprockets-es6

Javascript libraries are not managed.

It’s not a production gem.

 

Just don’t use it ! :)

 

ES2015 setup in Rails

Perfect setup

ES2015 setup in Rails

Browserify-rails

browserify will recursively analyze all the require() calls in your app in order to build a bundle you can serve up to the browser in a single <script> tag

 

repo

main lib repo

ES2015 setup in Rails

Browserify-rails

ES2015 setup in Rails

Browserify-rails

Summary:

  • Be able to use es6 modules - yes, but it needs a small hack

  • Libs are maintained by npm - yes

  • Libs css files are served too - no

  • Simple (less magic/sprockets hacks) - yes/no

 

ES2015 setup in Rails

Webpack

It’s a module bundler, but it also handles ‘javascript friends’ like images, fonts, css

 

https://github.com/nekath/es6-setup/tree/webpack

ES2015 setup in Rails

Webpack

Summary:

  • Be able to use es6 modules - yes

  • Libs are maintained by npm - yes

  • Libs css files are served too - yes

  • Simple (less magic/sprockets hacks) - yes

 

What we will cover from ES2015?

  1. Arrow functions
  2. Classes
  3. Enhanced Object Literals
  4. Interpolation of strings.
  5. Destructing.
  6. Default and spread args.
  7. Let, const and old var.
  8. Iterators.
  9. Modules.
  10. Array and Object API.
  11. Promises.

Arrow functions

let array = [1, 2, 3];

let newArray = array.map( (item) => {
    return item * 2;
});

Major change is that arrow function

share the same this as their surroundings!

(like fat arrow in CoffeeScript)

Classes

// ---- EXAMPLE FROM
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;

        return Math.sqrt(dx*dx + dy*dy);
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2));

But JavaScript is still prototype based inherited, so classes are only syntax sugar :)

What is new? Constructors, static functions

and super calls

Enhanced Object Literal Part 1

Shorthand Property Names

// Old way
var a = "foo", b = "bar";
var obj = { a: a, b: b};

// New way - shorthand property names
var a = "foo", b = "bar";
var obj = { a, b};

// Old way
var obj = {
    someFunction: function(params) {
        // ...
    }
};

// New way - shorhand function names
var obj = {
    someFunction(params) {
        // ...
    }
};

Enhanced Object Literal Part 2

Computed Property Names

var prop = "foo";
var obj = {
  [prop]: "hey",
  ["b" + "ar"]: "there",
};

// ---> obj["foo"] == "hey"; obj["bar"] == "there";

Template strings Part 1

Bye, bye, CoffeeScript

var name = "Bob", time = "today";
var string = `Hello ${name}, how are you ${time}?`;

Have you noticed?

What looks strange here?

Template strings Part 2

Bye, bye, CoffeeScript

var a = 5;
var b = 10;

function taggingFunction(strings, ...values) {
  console.log(strings[0]); // "Hello "
  console.log(strings[1]); // " world "
  console.log(values[0]);  // 15
  console.log(values[1]);  // 50

  return "Bazinga!";
}

taggingFunction`Hello ${ a + b } world ${ a * b}`;
// What's the result here?

Remember about security - tagged template strings should not be created by untrusted users.

Destructing Part 1

// list matching
var [a, , b] = [1, 2, 3]; // or var [a, _, b] (...)

// object matching
var { newX: x, newY: y } = getPoint(); // #getPoint returns { x: someX, y: someY }

// object matching shorthand
var { x, y } = getPoint();

// destructing in function params
function greetings({name: x}) {
    console.log(`Hello, ${x}!`);
};

greetings({name: "Foo Bar"});

It fails silently, returning just undefined.

Destructing Part 2

// swapping vars

var a = 1, b = 3;
[a, b] = [b, a]; // nice, huh?

// multiple-value returns
function f() {
    return [1, 2, 3];
}

var [a, b, c] = f();

Default and spread args

// default args
function multiply(x, y = 1) {
    return x * y;
}
multiply(5); // 5

// rest arguments (remove needs for arguments propert on Function object
function f(x, ...y) {
    return x * y.length;
}
f(3, "hi", "ho", true); // 9

// spread is destructing the array to args
function f(x, y, z) {
    return x + y + z;
}
f(...[1, 2, 3]); // 6

Let, var and const

function varTest() {
  var x = 31;
  if (true) {
    var x = 71;  // same variable!
    console.log(x);  // 71
  }
  console.log(x);  // 71
}

function letTest() {
  let x = 31;
  if (true) {
    let x = 71;  // different variable
    console.log(x);  // 71
  }
  console.log(x);  // 31
}

Let is the new var, but safer

Let and const are block-scoped

var was declaring either globally on window or for whole function

Iterators

function idMaker(){
    var index = 0;
    return {
       next: function(){
           return {value: index++, done: false};
       }
    };
}

var it = idMaker();

console.log(it.next().value); // 0

Iterators must implement simple interface - return object with next method that returns object with next value and done flag

Iterables

// example from Babeljs.io

let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { done: false, value: cur }
      }
    }
  }
}

for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}

Iterables are objects that implements iterators

Predefined iterables are e.g. arrays

Modules

// lib/math.js
export function sum(a, b) {
    return a + b;
}

// app.js
import * as math from "lib/math";
math.sum(5, 7);

// e.g. in Emberjs:
// my-component.js
export default Ember.Component.extend({
    // ...
});

// some other component
import Component from "my-component";
export default Component.extend({
    // ...
});

Language-level support for modules for component definition

Array and Object API

[1, 2, 3, 4].includes(3) // true
"abc".repeat(3) // "abcabcabc"

["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Formerly supported as polyfills, now accessible

Promises

// chaining - the exit from callback hell
fetch("www.items.com/items").then( (result) => {
    this.items = result;
    return fetch("www.items.com/me");
}).then( (result) => {
    this.myCompany = result;
});

Already used in modern JS frameworks

Promises represent objects that eventually will become values

If you think you know how Promises work, check out this blog post

Linter

In Ember, you can set your tests to fail if Linter outputs any error

Use JSLint or ESLint in your code to quickly learn new ES6 features, improve your code quality and make it less buggy

Questions?

More to read

JavaScript ES6

By Kuba Niechcial

JavaScript ES6

Introduction to JS ES2015, covering most commonly used new features in day to day JS development. Previously presented on Netguru internal meetup by @jniechcial.

  • 1,168