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:
1for (var i = 0; i < 5; i++) {2 // your code3}4console.log(i); // 5
We arguably want i
to be confined to the for-expression. let
does it correctly:
1for (var i = 0; i < 5; i++) {2 // your code3}4console.log(i); // ReferenceError
let
s
- are block- not function-scoped.
- are not hoisted like
var
s.
This means if you call them in a block before the declaration you’ll get a reference error:
1console.log(foo); // ReferenceError2let foo = 5;
while the same is ok with a var
declaration:
1console.log(foo); // undefined (no error, though)2var foo = 5;
- Makes shadowing inside functions possible.
- It’s not possible to re-declare a
let
in same block in strict mode whilevar
allows it (which is probably not what you want):
1var foo = 1;2var foo = 1; // OK34let bar = 1;5let 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.
1const foo = 1;2foo = 5; // TypeError3foo++; // TypeError45const bar = { a: 5 };6bar = { b: 6 }; // TypeError7bar.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):
1function greet(name = "Mr X") {2 console.log(`Hello ${name}`);3}4greet("Hans"); // Hello Hans5greet(); // 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:
1function greet(name) {2 if (name === undefined) {3 var name = "Mr X";4 }5 console.log("Hello" + name);6}
Arrow functions
Fat arrow functions reduce the boilerplate of anonymous functions:
1const add = (a, b) => a + b;2const 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:
1const foo = (a, b) => {2 // do your thing3 return a + b;4};
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
1const name = "Fritz";2console.log(`Hello ${name}`); // 'Hello Fritz'34console.log(`First line5Second line6Third line7`); // 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:
1// Array destructuring:2const arr = [21, 42, 57];3// get them all:4const [foo, bar, baz] = arr;5// or just the second one:6const [, second];7console.log(bar) // 428console.log(second) // 42910// Object destructuring:11const obj = { a: 21, b: 42, c: 57 };12const { a, b, c } = obj;13console.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.