Category: EcmaScript 6 niceties

This is the second article of the EcmaScript 6 niceties serieES6 also known as ES2015 brought a truck-load of new features and structures into Javascript and renewed the language as we knew it. This serie will highlight a few of the ES6 niceties you might find useful in your next Javascript project.
Today’s article is about those funny dots; rest- and spread-operator.

When looking at ES6 code for the first time you’ll probably notice the usage of three dots which you haven’t seen in any code written in Javascript’s earlier standards (<= ES5).
These three dots don’t necessarily do the same job, as there are two operators using that three-dot-syntax.

Rest operator

“The rest” can be assigned to a variable, using the rest-operator. Look at these rest-arguments:

function replace(string, ...replacements) {
  // return another string;
}
function subtract(...numbersToSubtract) {
  return numbersToSubtract.reduce((sum, next) => sum - next);
}
subtract(10, 1, 2, 3); // 4

Note that the rest operator must be a function’s last parameter!

Spread operator

The spread operator is sort of the opposite of the rest-operator: It takes an array of values, and turns it into ‘something else’ which uses comma-seperation. This might sound a little foggy, but these examples will clearify this:

// function calls
function combine(...numbers) {
  return subtract(...numbers) + add(...numbers);
}
combine(10,1,2,3); // 4+16=20

// assignments
const x = [1,2,3]; // 1,2,3
const y = [...x,4,5,6]; // 1,2,3,4,5,6
const z = [4,5,6,...x]; // 4,5,6,1,2,3
// assignments that converts Set and Map to an Array
let set = new Set([1, 2, 3, 3, 3, 4, 5]),
    array = [...set]; // [1,2,3,4,5];
let map = new Map([ ["name", "Sjoerd"], ["age", 40] ]),
    array = [...map]; // [ ["name", "Sjoerd"], ["age", 40] ]

// destructuring
const [a,b,...z] = y
a===1
b===2
z===[3,4,5,6]

Nearby future

The last example is called destructuring. In ES6 you can destructure ‘iterables’ (Array, Map, Set) and objects.

const { name, age } = { name: 'Sjoerd', age: 40, isDeveloper: true }

But you can’t destructure an object using the spread-operator. That could be so useful, especially working with React JS, where you find yourself often extracting values from props and state object literals.

But that is coming our way; Object Rest Spread proposal is in stage 4 in the ECMAScript approval process.
Using this Babel plugin enables you to use it now already.

const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }
x===1
y===2
z==={ a: 3, b: 4 }

In React practice

let props = {};
props.foo = x;
props.bar = y;
const component = <Component {...props} />;

const props = { foo: 'default' };
const component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'

This is the first article of the EcmaScript 6 niceties serie. ES6 also known as ES2015 brought a truck-load of new features and structures into Javascript and renewed the language as we knew it. This serie will highlight a few of the ES6 niceties you might find useful in your next Javascript project.
Today’s article is about arrow functions.

Arrow functions have a different syntax than traditional Javascript functions (using =>), but they’re not just a shorthand notation; they behave differently in a few ways. I’ll show you a few common examples of when and how to use those functions, compared to Javascript prior to ES6.

Arrow function syntax – pretty short!

Look at the following piece of code. Here you see the arrow function assembling the tradition Javascript function. You can see the syntax is rather short, and you’ll see its variations get shorter and shorter 🙂

var es5Function = function(a,b) {
    return a + b;
};
let es6Function = (a,b) => { // rather similar to es5Function
    return a + b;
};
// note implicit return
let es6FunctionShorthand = (a,b) => a+b;
let es6DamnShort = y => y+2;

console.log( es5Function(1,2) ); // 3
console.log( es6Function(1,2) ); // 3
console.log( es6FunctionShorthand(1,2) ); // 3
console.log( es6DamnShort(1) ); // 3

As anonymous function

In Javascript you’ll be using anonymous function more than often 🙂 – they’re all over the place! Arrow functions can be quite handy right here, because of their short syntax and their different behavior. Let’s start rather simple, an event handler:

function doSomething() {
    console.log("Do something");
}
myButton.addEventListener('click', doSomething, true);

Here the function doSomething is used as an event-handler, and can be (re)used by other code.
Every now and then, you first need to take care of some things in a handler before you start calling reusable code. Sometimes the reusable function expects other parameters or you need to do / check something with the given arguments. For example with the event argument:

/* ES <= 5 */
myAnchor.addEventListener('click', function(event){
    event.preventDefault();
    doSomething();
}, true);

/* ES6 */
myAnchor.addEventListener('click', event=>{
    event.preventDefault();
    doSomething();
}, true);

Nothing new happened here, but your code gets a lot cleaner.
Remember how short arrow functions’ syntax can get. Imagine how much cleaner the following code becomes compared to its ES5 counterpart:

function doX(x){
    console.log(`Do ${x}`);
}

myButton.addEventListener('click', ()=>{
    doX("something");
}, true);
// it can get very short!
myButton.addEventListener('click', ()=>doX("anything"), true);

Doesn’t bind ‘this’

So far arrow function just makes your code cleaner, but still function as always. One of the main new behaviors you’ll get to use a lot is that it doesn’t (re)bind this.
Apart from when your using a callback for jQuery.each you’ll be using a workaround if you need to access this from within your (anonymous) callback / event-handler function. Often by declaring something like ‘var that = this;‘ before creating the anonymous function, and use that in stead of this.
Compare these two examples:

/* ES &lt; 5 */
var ES5Clickers = {
    init: function() {
        this.myButton = document.getElementById("butt");
        this.myAnchor = document.getElementById("link");

        this.myButton.addEventListener('click', this.doSomething, true);
        var that = this;
        this.myAnchor.addEventListener('click', function(event){
            event.preventDefault();
            /* this.doSomething(); // this.doSomething is not a function */
            that.doSomething();
        }, true);
    },
    doSomething: function() {
        console.log("ES5Clickers: Do something with this");
    }
};
ES5Clickers.init();

/* ES6 */
const ES6Clickers = {
    init() {
        this.myButton = document.getElementById("butt");
        this.myAnchor = document.getElementById("link");

        this.myButton.addEventListener('click', this.doSomething, true);
        this.myAnchor.addEventListener('click', (event)=>{
            event.preventDefault();
            this.doSomething(); // is all good now!
        }, true);
    },
    doSomething() {
        console.log("ES6Clickers: Do something with this");
    }
};
ES6Clickers.init();

Lambda

The short notation variations and implicit returns makes lambda kinda work a breeze:

const x = [{name:"Jane", age:20}, {name:"John", age:30}];
const y = x.map(z=>z.name); // return name of each object into the new array
console.log(y); // ["Jane", "John"]