Introduction

JavaScript has changed a lot in the last couple years with the biggest update coming in 2015 called EcmaScript Version 6. From then on new features were released on a yearly basis. In my mind these additions change the language from a toy language to something I love to code in everyday. Here I will present my favorite features of modern JavaScript, for a full list you can check out the language specification here.

let and const

Let’s start with a quick one. The var keyword in JavaScript has a couple gotchas because of it being function- and not block-scoped. One quick example:

for (var i = 0; i < 5; i++){
    // your code
}
console.log(i) // 5

We arguably want i to be confined to the for-expression. let does it correctly:

for (var i = 0; i < 5; i++){
    // your code
}
console.log(i) // ReferenceError

lets

  • are block- not function-scoped.
  • are not hoisted like vars.
    This means if you call them in a block before the declaration you’ll get a reference error:
console.log(foo) // ReferenceError
let foo = 5;

while the same is ok with a var declaration:

console.log(foo) // undefined (no error, though)
var foo = 5;
  • Makes shadowing inside functions possible.
  • It’s not possible to re-declare a let in same block in strict mode while var allows it (which is probably not what you want):
var foo = 1;
var foo = 1; // OK

let bar = 1;
let bar = 1; // SyntaxError

const

const works like let only that the variable binding is fixed, so a redeclaration is not possible. Note that const objects are still mutable, just not the binding. If you need immutable objects you can take a look at immutable.js.

const foo = 1;
foo = 5; // TypeError
foo++; // TypeError

const bar = { a: 5 };
bar = { b: 6 }; // TypeError
bar.c = 10; // OK. { a:5, c:10 }

Try to use const whenever you can. When somebody reads your code and sees a const they can be sure this variable binding will not change which means less mental overhead for them.

There are more subtle changes with the introduction of let and const which I might talk about in a future blog post. As a rule, though, always use let and const instead of var and prefer const to let.

Default function arguments

This is such a convenient functionality known from other languages like Python. In ES6 it looks like this (featuring template strings):

function greet(name='Mr X') {
    console.log(`Hello ${name}`);
}
greet('Hans') // Hello Hans
greet() // Hello Mr X

Before ES6 providing your own default arguments was clumsy and error-prone (remember that checking for a value with !foo could lead to errors because of falsy values:

function greet(name) {
    if (name === undefined) {
        var name = 'Mr X';
    }
    console.log('Hello' + name);
}

Arrow functions

Fat arrow functions reduce the boilerplate of anonymous functions:

const add = (a, b) => a + b;
const inc = a => a + 1; // dropping the parens is valid if there's only one argument

No function keyword needed. Also no return needed if it’s just a one-liner. If you need more space just surround the body in parenthesis and work with a return keyword:

const foo = (a, b) => {
    // do your thing
    return a + b;
}

Additionally they don’t bind this which removes the need of the often-seen var self = this construct in nested functions.

Template literals

These are used to

  • Build dynamic strings containing variables (or any expression really..)
  • Multi-line strings without having to end the line with a backslash
const name = 'Fritz';
console.log(`Hello ${name}`); // 'Hello Fritz'

console.log(`First line
Second line
Third line
`) // returns the same three lines

There’s also an advanced usage of this feature: Tagged template literals where you process the string with a function beforehand. Styled Components uses this feature extensively, for example.

Destructuring

Use this feature when you quickly want to pull out values from an array or object:

// Array destructuring:
const arr = [21, 42, 57];
// get them all:
const [foo, bar, baz] = arr;
// or just the second one:
const [, second];
console.log(bar) // 42
console.log(second) // 42

// Object destructuring:
const obj = { a: 21, b: 42, c: 57 };
const { a, b, c } = obj;
console.log(c) // 57;

This is just the tip of the iceberg for destructuring. You can extract deeply nested values, rename them and lots more. I will write more about this in the next part of the series.

Browser support

You can check the compatibility here or here. Basically all the features are supported in modern browsers with the still used IE11 lagging behind. It’s still recommended to use a transpiler like babeljs. It has a new feature called babel-preset-env in which you can define which browsers you want to support and it figures out itself if the features have to be transpiled or used natively.

With babeljs there’s no reason to wait to use these awesome features so go and incorporate them in your workflow. If you want some practice take a look at ES6 Katas.

In the next post we will take a look at advanced destructuring, tagged template literals, the Object[key] setting syntax, new array functions and some interesting feature proposals.



While you're here:

I'm available for work in Munich, Vienna or remotely. Shoot me an email.

Updated: