JavaScript: Everything From ES2016 to ES2019
AlbertoM
Posted on January 5, 2020
Hi, I am Alberto Montalesi, a full-stack self-taught developer. I create practical JavaScript tutorials and courses on my website inspiredwebdev.com to inspire other developers to grow and build the career that they want.
JavaScript
is a language in constant evolution and in the past few years, many new features have been added to the ECMAScript
specification.
This article is an extract of my book Complete Guide to Modern JavaScript and it covers the new additions of ES2016, ES2017, ES2018, ES2019 and was originally posted on my blog inspiredWebDev.
At the end of the article you will find a link to download a cheat sheet that summarizes everything.
Everything new in ES2016
ES2016 introduced only two new features:
Array.prototype.includes()
- The exponential operator
Array.prototype.includes()
The includes()
method will return true
if our array includes a certain element, or false
if it doesn't.
let array = [1,2,4,5];
array.includes(2);
// true
array.includes(3);
// false
Combine includes()
with fromIndex
We can provide .includes()
with an index to begin searching for an element. The default is 0, but we can also pass a negative value.
The first value we pass in is the element to search and the second one is the index:
let array = [1,3,5,7,9,11];
array.includes(3,1);
// find the number 3 starting from array index 1
// true
array.includes(5,4);
//false
array.includes(1,-1);
// find the number 1 starting from the ending of the array going backwards
// false
array.includes(11,-3);
// true
array.includes(5,4);
returned false
because, despite the array containing the number 5, it is found at index 2 but we started looking at position 4. That's why we couldn't find it and it returned false
.
array.includes(1,-1);
returned false
because we started looking at the index -1 (which is the last element of the array) and then continued from that point onward.
array.includes(11,-3);
returned true
because we went back to the index -3 and moved up, finding the value 11 on our path.
The exponential operator
Prior to ES2016 we would have done the following:
Math.pow(2,2);
// 4
Math.pow(2,3);
// 8
Now with the new exponential operator, we can do the following:
2**2;
// 4
2**3;
// 8
It will get pretty useful when combining multiple operations like in this example:
2**2**2;
// 16
Math.pow(Math.pow(2,2),2);
// 16
Using Math.pow()
you need to continuously concatenate them and it can get pretty long and messy. The exponential operator provides a faster and cleaner way of doing the same thing.
ES2017 string padding, Object.entries()
, Object.values()
and more
ES2017 introduced many cool new features, which we are going to see here.
String padding (.padStart()
and .padEnd()
)
We can now add some padding to our strings, either at the end (.padEnd()
) or at the beginning (.padStart()
) of them.
"hello".padStart(6);
// " hello"
"hello".padEnd(6);
// "hello "
We specified that we want 6 as our padding, so then why in both cases did we only get 1 space?
It happened because padStart
and padEnd
will go and fill the empty spaces. In our example "hello" is 5 letters, and our padding is 6, which leaves only 1 empty space.
Look at this example:
"hi".padStart(10);
// 10 - 2 = 8 empty spaces
// " hi"
"welcome".padStart(10);
// 10 - 6 = 4 empty spaces
// " welcome"
Right align with padStart
We can use padStart
if we want to right-align something.
const strings = ["short", "medium length", "very long string"];
const longestString = strings.sort(str => str.length).map(str => str.length)[0];
strings.forEach(str => console.log(str.padStart(longestString)));
// very long string
// medium length
// short
First, we grabbed the longest of our strings and measured its length. We then applied a padStart
to all the strings based on the length of the longest so that we now have all of them perfectly aligned to the right.
Add a custom value to the padding
We are not bound to just add a white space as padding, we can pass both strings and numbers.
"hello".padEnd(13," Alberto");
// "hello Alberto"
"1".padStart(3,0);
// "001"
"99".padStart(3,0);
// "099"
Object.entries()
and Object.values()
Let's first create an Object.
const family = {
father: "Jonathan Kent",
mother: "Martha Kent",
son: "Clark Kent",
}
In previous versions of JavaScript
we would have accessed the values inside the object like this:
Object.keys(family);
// ["father", "mother", "son"]
family.father;
"Jonathan Kent"
Object.keys()
returned only the keys of the object that we then had to use to access the values.
We now have two more ways of accessing our objects:
Object.values(family);
// ["Jonathan Kent", "Martha Kent", "Clark Kent"]
Object.entries(family);
// ["father", "Jonathan Kent"]
// ["mother", "Martha Kent"]
// ["son", "Clark Kent"]
Object.values()
returns an array of all the values whilst Object.entries()
returns an array of arrays containing both keys and values.
Object.getOwnPropertyDescriptors()
This method will return all the own property descriptors of an object.
The attributes it can return are value
, writable
, get
, set
, configurable
and enumerable
.
const myObj = {
name: "Alberto",
age: 25,
greet() {
console.log("hello");
},
}
Object.getOwnPropertyDescriptors(myObj);
// age:{value: 25, writable: true, enumerable: true, configurable: true}
// greet:{value: ƒ, writable: true, enumerable: true, configurable: true}
// name:{value: "Alberto", writable: true, enumerable: true, configurable: true}
Trailing commas in function parameter lists and calls
This is just a minor change to a syntax. Now, when writing objects we can leave a trailing comma after each parameter, whether or not it is the last one.
// from this
const object = {
prop1: "prop",
prop2: "propop"
}
// to this
const object = {
prop1: "prop",
prop2: "propop",
}
Notice how I wrote a comma at the end of the second property.
It will not throw any error if you don't put it, but it's a better practice to follow as it makes your colleague’s or team member’s life easier.
// I write
const object = {
prop1: "prop",
prop2: "propop"
}
// my colleague updates the code, adding a new property
const object = {
prop1: "prop",
prop2: "propop"
prop3: "propopop"
}
// Suddenly, he gets an error because he did not notice that I forgot to leave a comma at the end of the last parameter.
Shared memory and Atomics
From MDN:
When memory is shared, multiple threads can read and write the same data in memory. Atomic operations make sure that predictable values are written and read, that operations are finished before the next operation starts and that operation is not interrupted.
Atomics
is not a constructor, all of its properties and methods are static (just like Math
) therefore we cannot use it with a new operator or invoke the Atomics
object as a function.
Examples of its methods are:
- add / sub
- and / or / xor
- load / store
Atomics are used with SharedArrayBuffer
(generic fixed-length binary data buffer) objects which represent generic, fixed-length raw binary data buffer.
Let's have a look at some examples of Atomics
methods:
Atomics.add()
, Atomics.sub()
, Atomics.load()
and Atomics.store()
Atomics.add()
will take three arguments, an array, an index, and a value and will return the previous value at that index before performing an addition.
// create a `SharedArrayBuffer`
const buffer = new SharedArrayBuffer(16);
const uint8 = new Uint8Array(buffer);
// add a value at the first position
uint8[0] = 10;
console.log(Atomics.add(uint8, 0, 5));
// 10
// 10 + 5 = 15
console.log(uint8[0])
// 15
console.log(Atomics.load(uint8,0));
// 15
As you can see, calling Atomics.add()
will return the previous value at the array position we are targeting. when we call again uint8[0]
we see that the addition was performed and we got 15.
To retrieve a specific value from our array we can use Atomics.load
and pass two-argument, an array, and an index.
Atomics.sub()
works the same way as Atomics.add()
but it will subtract a value.
// create a `SharedArrayBuffer`
const buffer = new SharedArrayBuffer(16);
const uint8 = new Uint8Array(buffer);
// add a value at the first position
uint8[0] = 10;
console.log(Atomics.sub(uint8, 0, 5));
// 10
// 10 - 5 = 5
console.log(uint8[0])
// 5
console.log(Atomics.store(uint8,0,3));
// 3
console.log(Atomics.load(uint8,0));
// 3
Here we are using Atomics.sub()
to substract 5 from the value at position uint8[0]
which is equivalent to 10 - 5.
Same as with Atomics.add()
, the method will return the previous value at that index, in this case, 10.
We are then using Atomics.store()
to store a specific value, in this case, 3, at a specific index of the array, in this case, 0, the first position.
Atomics.store()
will return the value that we just passed, in this case, 3. You can see that when we call Atomics.load()
on that specific index we get 3 and not 5 anymore.
Atomics.and()
, Atomics.or()
and Atomics.xor()
These three methods all perform bitwise AND, OR and XOR operations at a given position of the array. You can read more about bitwise operations on Wikipedia at this link https://en.wikipedia.org/wiki/Bitwise_operation
ES2017 Async and Await
Keep reading... or just get the cheatsheets.
Thank you very much for reading. Follow me on DevTo or on my blog at inspiredwebdev or on twitter.
Disclaimer: Links to Amazon and Educative are affiliate links, purchases you make will generate extra commissions for me. Thank you
Posted on January 5, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.