Here are examples of everything new in ECMAScript 2016, 2017 - AkuCode
· ES2016
ECMAScript is the standard upon which JavaScript is based, and it’s often abbreviated to ES. Discover everything about ECMAScript, and the last features added in ES2016, aka ES7. ES7 officially known as ECMAScript 2016, was finalized in June 2016.
Compared to ES6, ES7 is a tiny release for JavaScript, containing just two features:
- Array.prototype.includes
- Exponentiation Operator
Array.prototype.includes()
This feature introduces a more readable syntax for checking if an array contains an element. With ES6 and lower, to check if an array contained an element you had to use indexOf, which checks the index in the array and returns -1 if the element is not there.
if (![1,2].indexOf(3)) {
console.log('Not found')
}
With these features introduced in ES7 we can do
if (![1,2].includes(3)) {
console.log('Not found')
}
Exponentiation Operator
The exponentiation operator ** is the equivalent of Math.pow(), but brought into the language instead of being a library function.
Math.pow(4, 2) == 4 ** 2
This feature is a nice addition to math-intensive JS applications. The ** operator is standardized across many languages including Python, Ruby, MATLAB, Lua, Perl and many others.
ES2017
ECMAScript is the standard upon which JavaScript is based, and it’s often abbreviated to ES. Discover everything about ECMAScript, and the last features added in ES2017, aka ES8. ECMAScript 2017, edition 8 of the ECMA-262 Standard (also commonly called ES2017 or ES8), was finalized in June 2017.
Compared to ES6, ES8 is a tiny release for JavaScript, but still it introduces very useful features:
- String padding
- Object.values
- Object.entries
- Object.getOwnPropertyDescriptors()
- Trailing commas in function parameter lists and calls
- Async functions
- Shared memory and atomics
String padding
The purpose of string padding is to add characters to a string, so it reaches a specific length. ES2017 introduces two String methods: padStart() and padEnd().
padStart(targetLength [, padString])
padEnd(targetLength [, padString])
Sample usage:
padStart() |
|
‘test’.padStart(4) | ‘test’ |
‘test’.padStart(5) | ‘_test’ |
‘test’.padStart(8) | ‘___test’ |
‘test’.padStart(8,’abcd’) | ‘abcdtest’ |
padEnd() |
|
‘test’.padEnd(4) | ‘test’ |
‘test’.padEnd(5) | ‘test_’ |
‘test’.padEnd(8) | ‘test___’ |
‘test’.padEnd(8,’abcd’) | ‘abcdtest’ |
Object.values()
This method returns an array containing all the object own property values.
Usage:
const person = { name: 'Fred', age: 87 }
Object.values(person) // ['Fred', 87]
Object.values() also work with arrays:
const people = ['Fred', 'Tony']
Object.values(people) // ['Fred', 'Tony']
Object.entries()
This method returns an array containing all objects own properties, as an array of [key, value] pairs.
const person = { name: 'Fred', age: 87 }
Object.entries(person) // [['name', 'Fred'], ['age', 87]]
const people = ['Fred', 'Tony']
Object.entries(people) // [['0', 'Fred'], ['1', 'Tony']]
getOwnPropertyDescriptors()
This method returns all its own (non-inherited) properties descriptors of an object. any object in JavaScript has a set of properties, and each of these properties has a descriptor. A descriptor is a set of attributes of a property, and it’s composed by a subset of the following:
- value: the value of the property
- writable: true the property can be changed
- get a getter function for the property, called when the property is read
- set: a setter function for the property, called when the property is set to a value
- configurable: if false, the property cannot be removed nor any attribute can be hanged, except its value
- enumerable: true if the property is enumerable
Object.getOwnPropertyDescriptors(obj) accepts an object, and returns an object with the set of descriptors.
In that way is this useful?
ES2015 gave us an Object.assign(),, which copies all enumerable own properties from one or more objects and return a new object. however, there is a problem with that because it does not correctly copy properties with non-default attributes. If an object, for example, has just setter, it’s not correctly copied to a new object, using Object.assign().
For example with
const person1 = {
set name(newName) {
console.log(newName)
}
}
This won’t work:
const person2 = {}
Object.assign(person2, person1)
But this will work:
const person3 = {}
Object.defineProperties(person3, Object.getOwnPropertyDescriptors(person1))
As you can see with a simple console test:
person1.name = 'x'
;('x')
person2.name = 'x'
person3.name = 'x'
;('x')
Person2 misses the setter, it was not copied over. The same limitation goes for shallow cloning object with Object.create().
Trailing commas
This the feature allows to have trailing commas in function declarations, and in functions calls:
const doSomething = (var1, var2) => {
//...
}
doSomething('test2', 'test2')
This change will encourage developers to stop the ugly “comma at the start of the line” habit.
Async functions
ES2017 introduced the concept of async functions, and it’s the most important change introduced in this ECMAScript edition. Async functions are a combination of promises and generators to reduce the boilerplate around promises, and the “don’t break the chain” limitation of chaining promises.
Why they are useful
It’s a higher-level abstraction over promises. When promises were introduced in ES2015, they were meant to solve a problem with asynchronous code, and they did, but over the 2 years that separated ES2015 and ES2017, it was clear that promises could not be the final solution. A promise was introduced to solve the famous callback hell problem, but they introduced complexity on their own, and syntax complexity. They were good primitives around which a better syntax could be exposed to the developers: enter async functions.
A quick example
Code making use of asynchronous functions can be written as
function doSomethingAsync() {
return new Promise(resolve => {
setTimeout(() => resolve('I did something'), 3000)
})
}
async function doSomething() {
console.log(await doSomethingAsync())
}
console.log('Before')
doSomething()
console.log('After')
The above code will print the following to the browser console:
Before
After
I did something //after 3s
Multiple async functions in series
Async functions can be chained very easily, and the syntax is much more readable than with plain promises:
function promiseToDoSomething() {
return new Promise(resolve => {
setTimeout(() => resolve('I did something'), 10000)
})
}
async function watchOverSomeoneDoingSomething() {
const something = await promiseToDoSomething()
return something + ' and I watched'
}
async function watchOverSomeoneWatchingSomeoneDoingSomething() {
const something = await watchOverSomeoneDoingSomething()
return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then(res => {
console.log(res)
})
Shared memory and Atomics
WebWorkers are used to create a multithreaded program in the browser. They offer a messaging protocol via events. Since ES2017, you can create a shared memory array between web workers and their creator, using a SharedArrayBuffer. Since it’s unknown much time writing to a shared memory portion takes to propagate, Atomics are away to enforce that when reading a value, any kind of writing operation is completed