Upgrade your JavaScript
In 2019, most of my personal (web) projects are written in TypeScript, because well, it's just an awesome extension of plain old JavaScript.
Many developers I know agree, and you could even say, "Typescript won", regarding competing projects like CoffeeScript, Dart, or even plain JS.
To re-capture ECMAScript (the JavaScript specification) and its relation to TypeScript, have a look at the following image (from this blog post):
You can read it like follows:
- ES5: "old" JavaScript (2009)
- ES6: "newer" Javascript (2015)
Using ES 6
Sometimes, when "pure" JavaScript is needed or I'm working on something that can not be TypeScript (because it has to be supported directly by the browser), I mostly see old, hacky JavaScript, and am tempted to also write in the same old, ES5 style.
But which version is safe to use? This compatibility table has a detailed overview for all ES 6 features and their support in the different browsers (and backend servers like Node).
To put it simple: All current major browsers have full support (> 95%) for ES 6. Here is a table which shows when the Browser started support for ES 6 (from w3schools):
Browser | Version | Date |
---|---|---|
Chrome | 51 | May 2016 |
Firefox | 54 | Jun 2017 |
Edge | 14 | Aug 2016 |
Safari | 10 | Sep 2016 |
Opera | 38 | Jun 2016 |
So, definitely time to start using ES6!
Features
The excellent page ES 6 features has a nice, extensive list of features, from which I'd like to point a few out.
Classes
Finally, "real" classes!
class Pet {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hi, my name is ${this.name}`);
}
}
You can create new instances just as in any other language:
let pet = new Pet("Bello");
pet.greet(); // output: Hi, my name is Bello
Block-scoped variables with let/const
Declare constants and variables without exposing them globally.
const PI = 3;
for (let i = 0; i < 2; i++) {
console.log(i); // output: 0 1
}
// at this point, i is not defined
console.log(i); // output: "ReferenceError: can't access [...] `i' before initialization"
let i = 5;
console.log(i); // output: 5
Arrow functions (for “this”….)
No more var that = this
, just use fat arrow function expressions and preserve context. They also come in handy for many Array functions which expect a function callback:
let arr = ['foo', 'bar', 'foobar'];
let filtered = arr.filter(entry => entry.includes('bar'));
console.log(filtered); // output: ['bar', 'foobar']
String interpolations
As you can see with the class above, you can easily use string interpolation to insert a variable into a defined string constant:
let name = 'Mary';
console.log(`Hi, my name is ${name}!`); // output: Hi, my name is Mary!
Default params
You can define default params for functions:
function greet(name = 'you') {
console.log(`Hello, ${name}`);
}
console.log(greet()); // output: Hello, you
console.log(greet('Daniel')); // output: Hello, Daniel
Array spread
The new spread syntax lets you easily turn an array into multiple single values, for example in a function call:
function add(a, b, c, d) {
return a + b + c + d;
}
let arr = [1, 1, 2, 3];
console.log(add(...arr)); // output: 7
Import/export modules
After community driven modules (CommonJS and AMD/RequireJS), ES6 now supports modules itself, so it is easier to use and reuse code. You can either import exported members from certain modules, or import whole modules:
import defaultExport from "module-name";
import * as name from "module-name";
You can read a detailed explanation of modules here.
Set and Map
ES6 has native support for Set and Map data structures:
let s = new Set();
s.add(1);
s.add(2);
s.add(1); // if a value already exists, nothing will happen
console.log(s.size); // output: 2
console.log(s.has(2)); // output: true
s.clear(); // set is now empty again
An example with Map:
let m = new Map();
m.set('a', 1);
m.set('b', 2);
m.set('a', 3); // we can override an existing value
console.log(m.has('b')); // output: true
console.log(m.get('a')); // output: 3
m.clear(); // map is now empty again
Object.assign()
To clone or merge an object, use Object.assign()
:
let obj1 = {a: 1, b: 2};
let obj2 = Object.assign({a: 0}, obj1);
console.log(obj2); // output: {a: 1, b: 2}
Array.find
As other Array functions, find()
will accept a function, and will return the first element found for which the function returns true:
let arr = [1, 1, 2, 3, 5, 8, 11];
console.log(arr.find(e => e % 2 == 0)); // output: 2
String.startsWith/endsWith/includes
Finally some more readable alternatives to indexOf
:
let name = 'JavaScript';
console.log(name.startsWith('Java')); // output: true
console.log(name.endsWith('Java')); // output: false
console.log(name.includes('Java')); // output: true
Promises
ES6 has built-in support for Promises:
let flag = true;
let myPromise = new Promise((resolve, reject) => {
if (flag) {
resolve(`Flag: ${flag}`);
} else {
reject('Flag was set to false :-(');
}
});
myPromise.then(msg => console.log(msg)); // output: Flag: true