ECMAScript 6
under the microscope
Andrei Pfeiffer
 @pfeiffer_andrei       
 /andreipfeiffer
// code designer
// co-organizer & speaker
// dev author
5620 LOC
// Client: 1500 src + 1350 tests
// Server: 2200 src + 570  tests
/*
- arrow functions
- modules
- object enhanced literals
- built-in extensions
- SystemJS
- Karma tests + coverage
- build system + workflow setup
*/
5 days
build-in extensions
// new methods on existing prototypes
String.startsWith()
var str = "es6 features";

str.startsWith("es6");
// true
// instead of ES5

( str.indexOf("es6") === 0 );
String.endsWith()
var str = "es6 features";

str.endsWith("features");
// true
// instead of ES5

var str = "es6 features",
    s   = "features";

( str.indexOf(s, str.length - s.length) > -1 );
String.includes()
var str = "es6 features";

str.includes("es6");
// true

str.includes("es6", 1);
// false
// instead of ES5

(str.indexOf("es6") > -1);
Array.find()
var arr = [
  { a: 1, b: 10 },
  { a: 2, b: 20 }
];

arr.find(item => item.a > 0);
// { a: 1, b: 10 }
// instead of ES5

arr.filter(function(item) {
    return item.a > 0;
})[0];
Array.findIndex()
var arr = [
  { a: 1, b: 10 },
  { a: 2, b: 20 }
];

arr.findIndex(item => item.a > 0);
// 0
// instead of ES5

var index;
arr.some(function(item, i) {
    if ( item.a > 1 ) {
        index = i;
        return true;
    }
});
Array.includes()
var arr = [1, 2, 3];

arr.includes(2);
// true

arr.includes(2, 2);
// false
var arr = [{}];

arr.includes({});
// false
var obj = {},
    arr = [obj];

arr.includes(obj);
// true
Array.fill()
var arr = [1, 2, 3];

arr.fill( null );
// [null, null, null]
// instead of ES5

arr.forEach((item, index) => {
    arr[index] = null;
});
// array with fixed number
// of repeating elements

var arr = Array(3).fill( null );
// [null, null, null];
Object.assign()
var o1 = { a: 1 },
    o2 = { a: 2, b: 2 };

var o3 = Object.assign({}, o1, o2);
// {a: 2, b: 2}
// no more

$.extend();            // jQuery
angular.extend();      // AngularJS
_.extend               // underscore
require(util)._extend; // Node.js
Node.js
4.x
4.x
flag
Babel
5.x
plugin
plugin
support
  
*
Object.assign()
Array.includes()
object enhanced literals
// easier object definition
shorthand 
methods & properties
var name = "Andrei Pfeiffer";

var obj = {
    name,
    getName() {
        return this.name;
    }
};
// instead of ES5

var obj = {
    name: name,
    getName: function() {
        return this.name;
    }
};
computed 
methods & properties
var name = "Name";

var obj = {
    ["last" + name]: "Pfeiffer",
    ["get" + name]() { /*...*/ }
};

obj.firstName;
obj.getName();
// instead of ES5

var obj = {};
obj["last" + name] = "Pfeiffer";
obj["get" + name]  = function() { /*...*/ };

modules
// code isolation
// module pattern

var myModule = (function() {

    "use strict";

    var secret = 'secret';

    return {
        getSecret: function() {
            return secret;
        }
    };

})();
no more IIFE
// no global scope pollution
var myModule = (function() {

    "use strict";

    var secret = 'secret';

    return {
        getSecret: function() {
            return secret;
        }
    };

})();
no more "use strict"
// implicit Strict Mode
var myModule = (function() {

    "use strict";

    var secret = 'secret';

    return {
        getSecret: function() {
            return secret;
        }
    };

})();
var secret = 'secret';

export function getSecret() {
    return secret;
};
secure APIs
// exports are immutable
// secret.js

var secret = 'secret';

export function getSecret() {
    return secret;
};
// secret.js

export const secret = 'secret';
// app.js

import {secret} from "./secret";

console.log( secret );
// "secret"

secret = "no secret";
// TypeError
zero globals
long import lists
// userController.js

import config from './config';
import filters from './filters';
import { search } from './utils';
import UserService from './services/user';

/* ... */
arrow functions
// anonymous function expressions
// replace "function" with "=>"
// and move it after params

var foo = function(id) => {
    return request.get(id);
};
inline simple functions
// 2 LOC less
// single statement functions

var foo = id => request.get(id);
// instead of ES5

var foo = function(id) {
    return request.get(id);
};
// no inline for 2 statements

var foo = (id) => {
    validate(id);
    return request.get(id);
};
// or for long single statements

var foo = (id) => {
    validate(id)
        .then( request.get(id) )
        .then( (data) => render(data) );
};
implicit this
// auto-bound to object
// this references outer context (: yey

var obj = {
    name: '',
    init() {
        $.get().then(x => {
            this.name = x;
        });
    }
};
// instead of ES5

var obj = {
    name: '',
    init: function() {
        var self = this;
        $.get().then(function(x) {
            self.name = x;
        });
    }
};
// caution with jQuery events

$('a').click(function() {
    $(this).toggleClass('active');
});

// this = DOM element
// this references outer context ): shit

$('a').click(() => {
    $(this).toggleClass('active');
});

// this = undefined
// caution with Angular repeaters

<div ng-repeat="items">
    <button ng-click="do()"></button>
</div>
// this references iterated item

$scope.do = function() {
    console.log(this);
};

// [Object]
// this references outer scope

$scope.do = () => {
    console.log(this);
};

// undefined
// solution: pass data explicitly

<div ng-repeat="items">
    <button ng-click="do($data)"></button>
</div>
// don't rely on context

$scope.do = (data) => {
    console.log(data);
};

// [Object]
implicit return
// aka "expression closure"
// without braces, implicit return

var foo = () => 1;

foo(); // 1
// with braces, no implicit return

var foo = () => { 1 };

foo(); // undefined
// requires explicit return

var foo = () => { return 1; };

foo(); // 1
// we can implicitly return arrays

var foo = () => [1, 2];

foo(); // [1, 2]
// but not objects

var foo = () => {a: 1};

foo(); // undefined
// objects need to be wrapped

var foo = () => ({a: 1});

foo(); // {a: 1}
conclusions
built-in extensions
// nice to have
// write less, do more
enhanced object literals
// probably best addition
modules
// non-trivial to setup
// great for FP, composition
arrow functions
// great for callbacks (!!! this)
// declarations are still valid
..?
thank you

JavaScript Vanilla #5 - ES6 under the microscope

By Andrei Pfeiffer

JavaScript Vanilla #5 - ES6 under the microscope

In this presentation I will talk about some of the features introduced in ES6, namely: useful new methods on existing prototypes, object enhanced literals, the benefits of modules & the pros & gotchas of arrow functions.

  • 1,133