ES2015 introduced lots of features, like arrow functions, class syntax for object creation and inheritance, let
and const
, and many other new features. In the next few years, more great features will be introduced into the language and the standard library. ES2016 was a minor revision with new features, such as introducing the includes
function to arrays and the exponential operator. ES2017 introduced more features like Object.values
and Object.entries
and string functions like padStart
and padEnd
, and async
and await
. These are handy features that bring even more convenience to JavaScript developers, making JavaScript app development even easier.
ES2016 Features
Array.includes
Array.includes
checks if an item exists in an array. It takes a number or string, which the function can compare as the first argument and the index to search from as the second argument. The second argument can be positive or negative.
const array = [1,2,3];
const includesTwo = array.includes(2); // returns true
We can also search the array starting with a negative index, then the function search beginning from the computed index, which is the length of the array plus the second argument. So if we write:
array.includes(2, -2);
Then the includes
function will search starting with index 3 +(-2).
This means that array.includes(2, -2);
should return true
. If the absolute number of what you pass in is bigger than the length, then the whole array is searched.
The includes
function was also added to TypedArray types like Int8Array , or Uint8Array .
Exponential operator
The exponential operator is another new feature of ES2016. The exponential operator is denoted by **
. It’s the new syntax for computing exponential values, which is the alternative to the Math.pow
function. For example, to compute 2 to the power of 3, we can write,
2**3
which is 8. Note that in JavaScript, it’s impossible to write ambiguous expressions when we combine the exponential operator with unary operators like -
, so something like -2**2
is invalid in JavaScript. However, -(2**2)
is valid since it’s unambiguous in that we know that the value is -4 since the exponential is in parentheses and the negative sign is outside.
We can force the base of the exponentiation expression to be a negative number by writing:
(-2)**2
So this means the base
has to be in parentheses.
ES2017 Features
Object.values
The Object.values
lets us get an array with the values of an object in an array. The values are returned in the same order as it is provided by the for...in
loop, except that Object.values
do not return values that are in the prototype chain.
For example, we can write:
const obj = { a: 1, b: 2 };
console.log(Object.values(obj)); // [1, 2]
const obj = { 0: 'd', 1: 'e', 2: 'f' };
console.log(Object.values(obj)); // ['d', 'e', 'f']
const obj2 = { 100: 'd', 2: 'e', 7: 'f' };
console.log(Object.values(obj2)); // ['e', 'f', 'd']
console.log(Object.values('abc')); // ['a', 'b', 'c']
As we can see, Object.values
works with objects and strings. If the keys are numbers, then they are returned in with the keys in increasing order, like in the obj2
example above. For strings, it returns an array of the individual characters of the string.
Object.entries()
The Object.entries
function returns an array with each entry being the key-value pairs in their individual arrays. The entries are returned in the same order as it is provided by the for...in
loop, except that Object.values
do not return values that are in the prototype chain. As with any object, we can sort the array to get the entries in the order we want with the sort
function.
For example, we can write:
const obj = { foo: 1, bar: 2 };
console.log(Object.entries(obj)); // [ ['foo', 1], ['bar', 2] ]
const obj = { 0: 'x', 1: 'y', 2: 'z' };
console.log(Object.entries(obj)); // [ ['0', 'x'], ['1', 'y'], ['2', 'z'] ]
const obj2 = { 100: 'x', 2: 'y', 7: 'z' };
console.log(Object.entries(obj2)); // [ ['2', 'x'], ['7', 'y'], ['100', 'z'] ]
console.log(Object.entries('abc')); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
console.log(Object.entries(100)); // [ ]
const obj = { a: 1, b: 2, c: 3};
for (const [key, value] of Object.entries(obj)) {
console.log(`${key} ${value}`); // "a 1", "b 2", "c 3"
}
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`); // "a 1", "b 2", "c 3"
});
In the above examples, we can see that Object.entries
return an array of key-value pairs with each entry as an array with the key being the first element and the value being the second element. If the keys are integers, then they are sorted in ascending numerical order. So Object.entries(obj2)
returns [ ['2', 'x'], ['7', 'y'], ['100', 'z'] ]
. It also works with strings with the individual characters return with the index of the characters as the key, so the key is the index of the string, which is the first element of each entry, and the individual character is the value of the string, which is returned as the second character. For objects that have no properties, like numbers and booleans, Object.entries
returns an empty array.
The array returned by Object.entries
can be converted to a Map
object. It can be used like in the following example:
const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));
console.log(map); // Map { a: 1, b: 2 }
String.padStart()
The padStart()
function adds a string the number of times before a string until it reaches the length that you specify. The function takes two parameters. The first is the target length of your string. If the target length is less than the length of your string, then the string is returned as-is. The second parameter is the string that you want to add the padding with. It’s an optional parameter and it defaults to ' '
is nothing is specified.
For example, we can write the following:
'def'.padStart(10); // " def"
'def'.padStart(10, "123"); // "1231231def"
'def'.padStart(6,"123465"); // "abcdef"
'def'.padStart(8, "0"); // "00000def"
'def'.padStart(1); // "def"
Note that each string is filled up to the target length with the string in the second argument. The whole string in the second argument may not always be included. Only the part that lets the function fill the string up to the target length is included.
String.padEnd()
The padEnd()
function adds a string the number of times after a string until it reaches the length that you specify. The function takes 2 parameters. The first is the target length of your string. If the target length is less than the length of your string, then the string is returned as is. The second parameter is the string that you want to add the padding with. It’s an optional parameter, and it defaults to ' '
is nothing is specified.
For example, we can write the following:
'def'.padEnd(10); // "def "
'def'.padEnd(10, "123"); // "def1231231"
'def'.padEnd(6,"123465"); // "defabc"
'def'.padEnd(8, "0"); // "def00000"
'def'.padEnd(1); // "def"
Object.getOwnPropertyDescriptors()
The Object.getOwnPropertyDescriptors()
function returns all the property descriptors of an object.
For example, we can use it like the following code:
const obj = {
a: 1
};const descriptors = Object.getOwnPropertyDescriptors(obj);
The descriptors
object should have:
{
a: {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
}
Async and Await
With async
and await
, we can shorten promise code. Before async
and await
, we have to use the then
function, we make to put callback functions as an argument of all of our then
functions. This makes the code long is we have lots of promises. Instead, we can use the async
and await
syntax to replace the then
and its associated callbacks as follows. For example, we have the code to make requests to the back end with the Fetch API:
const APIURL = "http://localhost:3000";
const subscribe = async data => {
const response = await fetch(`${APIURL}/subscribers`, {
method: "POST",
mode: "cors",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
return response.json();
};
window.onload = () => {
nameForm.method = "post";
nameForm.target = "_blank";
nameForm.action = "";
nameForm.addEventListener("submit", async e => {
e.preventDefault();
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
const email = document.getElementById("email").value;
let errors = [];
if (!firstName) {
errors.push("First name is required.");
}
if (!lastName) {
errors.push("Last name is required.");
}
if (!email) {
errors.push("Email is required.");
}
if (!/\[^@\]+@\[^\.\]+\..+/.test(email)) {
errors.push("Email is invalid.");
}
if (errors.length > 0) {
alert(errors.join(" "));
return;
}
try {
const response = await subscribe({
firstName,
lastName,
email
});
alert(`${response.firstName} ${response.lastName} has subscribed`);
}
catch (error) {
alert(error.toString());
}
});
};
We replaced the then
and callbacks with await
. Then we can assign the resolved values of each promise as variables. Note that if we use await
for our promise code then we have to put async
in the function signature as we did in the above example. To catch errors, instead of chaining the catch
function in the end, we use the catch
clause to do it instead. Also, instead of chaining the finally
function at the bottom to run code when a promise ends, we use the finally
clause after the catch
clause to do that instead.
In the code above, we got the resolved value of the promise assigned to a variable instead of getting the value in the callback of the then
function, like in the const response = await subscribe({...})
line above.
async
functions always return promises and cannot return anything else like any other function that uses promises. In the example above, we used the promised based Fetch API and async
and await
syntax, we showed that we can chain promises in a much shorter way than with the then
function with callbacks passed in as an argument.
ES2016 and 2017 gave us convenient features that enhance the already great syntactic sugar and functions that were added to ES2015, which was a significant improvement over its predecessor. These two versions of JavaScript make JavaScript development even better with new Object, string, and Array methods and shorthand for chaining promises.