JavaScript Guide, Part 9: ES7, ES8, and ES9 Features Overview
- Transfer
- Tutorial
Today, in the ninth part of the translation of the JavaScript guide, we will review the features that have emerged in the language thanks to the standards ES7, ES8 and ES9.
→ Part 1: first program, language features, standards
→ Part 2: code style and program structure
→ Part 3: variables, data types, expressions, objects
→ Part 4: functions
→ Part 5: arrays and cycles
→ Part 6: exceptions, semicolon, template literals
→ Part 7: strict mode, this keyword, events, modules, mathematical calculations
→ Part 8: an overview of the capabilities of the ES6 standard
→ Part 9: an overview of the capabilities of the ES7, ES8, and ES9 standards
The ES7 standard, which, in accordance with official terminology, is called ES2016, was released in the summer of 2016. Compared to ES6, it brought not so much new to the language. In particular, we are talking about the following:
The method is
In accordance with the JavaScript type conversion rules, the number is
If in a similar situation, assuming that
In this case, it turns out that the design
Using the method of
In this case, the construction
The exponentiation operator performs the same function as the method
This operator can be considered a nice addition JS, which is useful in applications that perform certain calculations. A similar operator exists in other programming languages.
Standard ES8 (ES2017) was released in 2017. He, like ES7, introduced not so much new to the language. Namely, we are talking about the following possibilities:
Two new object methods appeared in ES8
The method
Here
The method is
Consider examples of the use of these methods.
Here, when used
This method returns an array containing the values of the object's own properties, that is, those properties that the object itself contains, and not those that are accessible to it through a chain of prototypes.
Here's how to use it.
This method also applies to arrays.
This method returns an array, each element of which is also an array containing, in format
When applying this method to arrays, the indexes of elements are displayed as keys, and what is stored in the array at the corresponding indices is displayed as values.
This method returns information about all the properties of an object. Associated with attributes of objects are sets of attributes (descriptors). In particular, we are talking about the following attributes:
Here is how to use this method.
It takes an object whose property information you want to know, and returns an object containing this information.
Why do you need this method? The fact is that it allows you to create small copies of objects, copying, among other properties, getters and setters. This could not be done using the method for copying objects
In the following example, there is an object with a setter that outputs, using
Let's try to copy this object using the method
As you can see, this approach does not work. The property
Now let's copy the object using the methods
Here in the copy of the object the setter remained.
It should be noted that the limitations characteristic of
This feature allows you to leave a comma at the end of the list of parameters or arguments, respectively, when you declare and when you call functions.
This improves the usability of version control systems. Namely, we are talking about the fact that, when adding new parameters to a function, it is not necessary to change the existing code just to insert a comma.
The ES2017 standard introduced a design
Asynchronous functions are a combination of promises and generators, they simplify constructions, for which a large amount of template code and inconvenient promises chains were required to describe them. In fact, this is a high-level abstraction over promises.
When promises appeared in the ES2015 standard, they were designed to solve existing problems with asynchronous code, which they did. But in the two years that have shared the ES2015 and ES2017 standards, it has become clear that promises cannot be considered the final solution to these problems.
In particular, promises were aimed at solving the problem of “hell callbacks”, but, having solved this problem, they showed themselves not with the best hand due to the complication of the code in which they are used. As a matter of fact, the design
Consider an example.
This code will display the following in the console.
As you can see, after the call, the
If necessary, asynchronous functions can form something like call chains. Such constructions have better readability than something similar, based solely on promises. This can be seen in the following example.
Here we are talking about the SharedArrayBuffer object , which allows us to describe shared memory areas, and the Atomics object , which contains a set of atomic operations in the form of static methods. Details about the possibilities that these objects give to the programmer can be found here .
ES9 (ES2018) is the latest version of the standard at the time of publication of this material. Here are its main features:
We have already spoken about the rest and spread operators that appeared in ES6 and can be used to work with arrays. Both of them look like three points. The rest operator, in the following example of destructuring an array, allows you to place its first and second elements into constants
The operator
Now, using the same approach, you can work with objects. Here is an example of using the rest operator in a destructive assignment operation.
Here is the spread operator used when creating a new object based on an existing one. This example continues the previous one.
The new design
It should be noted that such cycles should be used in asynchronous functions - just as it is done when working with a design
If the promise is successfully resolved, the next method is called
In regular expressions, it was possible to retrospectively check strings (
The possibility of advanced checks using a construct
The construction
In retrospective verification, as already mentioned, the construction is used
The inverse operation described can be performed with the help of the construction
In regular expressions, you can use a class
In Unicode, each character has a set of properties. These properties are specified in curly brackets of the group
The property
There are many other similar properties that are used the same way as described above. Among them -
Here, for example, how to use the property to
Details on these properties can be read here .
Captured character groups in ES2018 can be given names. Here's what it looks like.
Without the use of named groups, the same data would be available only as elements of an array.
The use of the flag
With this material, we complete the publication of translations of this JavaScript guide. Hopefully, these publications have helped those who have not worked with JavaScript before, to take their first steps in programming in this language.
Dear readers! If you have not written in JS before and mastered this language in this manual, please share your impressions.
→ Part 1: first program, language features, standards
→ Part 2: code style and program structure
→ Part 3: variables, data types, expressions, objects
→ Part 4: functions
→ Part 5: arrays and cycles
→ Part 6: exceptions, semicolon, template literals
→ Part 7: strict mode, this keyword, events, modules, mathematical calculations
→ Part 8: an overview of the capabilities of the ES6 standard
→ Part 9: an overview of the capabilities of the ES7, ES8, and ES9 standards
ES7 standard
The ES7 standard, which, in accordance with official terminology, is called ES2016, was released in the summer of 2016. Compared to ES6, it brought not so much new to the language. In particular, we are talking about the following:
- Method
Array.prototype.includes()
. - Exponentiation operator.
ArArray.prototype.includes () method
The method is
Array.prototype.includes()
designed to check the presence of an element in the array. Finding the desired in the array, it returns true
, not finding - false
. Prior to ES7 indexOf()
, a method served to perform the same operation , which returns, if an element is found, the first index by which it can be found in the array. If the indexOf()
item does not find it, it returns a number -1
. In accordance with the JavaScript type conversion rules, the number is
-1
converted to true
. As a result, to verify the results of the work, indexOf()
it was necessary to use a not very convenient construction of the following type.if ([1,2].indexOf(3) === -1) {
console.log('Not found')
}
If in a similar situation, assuming that
indexOf()
, without finding an element, returns false
, to use something like the one shown below, the code will not work correctly.if (![1,2].indexOf(3)) { //неправильно
console.log('Not found')
}
In this case, it turns out that the design
![1,2].indexOf(3)
gives false
. Using the method of
includes()
such comparisons look much more logical.if (![1,2].includes(3)) {
console.log('Not found')
}
In this case, the construction
[1,2].includes(3)
returns false
, the operator !
converts this value into, true
and a message is received in the console stating that the required element in the array was not found.▍Exponentiation operator
The exponentiation operator performs the same function as the method
Math.pow()
, but it is more convenient to use it than the library function, since it is part of the language.Math.pow(4, 2) == 4 ** 2//true
This operator can be considered a nice addition JS, which is useful in applications that perform certain calculations. A similar operator exists in other programming languages.
ES8 standard
Standard ES8 (ES2017) was released in 2017. He, like ES7, introduced not so much new to the language. Namely, we are talking about the following possibilities:
- Supplement lines to a given length.
- Method
Object.values()
. - Method
Object.entries()
. - Method
Object.getOwnPropertyDescriptors()
. - Trailing commas in function parameters.
- Asynchronous functions.
- Shared memory and atomic operations.
▍Add lines up to a given length
Two new object methods appeared in ES8
String
- padStart()
and padEnd()
. The method
padStart()
fills the current line with another line until the final line reaches the desired length. Filling occurs at the beginning of the line (left). Here is how to use this method.str.padStart(targetLength [, padString])
Here
str
is the current line, targetLength
is the length of the final line (if it is less than the length of the current line - this line will be returned unchanged), padString
- optional parameter - the line used to fill the current line. If the parameter is padString
not specified, the space character is used to add the current line to the specified length. The method is
padEnd()
similar padStart()
, but the line is filled to the right. Consider examples of the use of these methods.
const str = 'test'.padStart(10)
const str1 = 'test'.padEnd(10,'*')
console.log(`'${str}'`) //' test'console.log(`'${str1}'`) //'test******'
Here, when used
padStart()
with only the desired length of the result line, spaces were added to the beginning of the source line. When used padEnd()
with the indication of the length of the final line and the line, characters were added to the end of the original line to fill it *
.Object Method Object.values ()
This method returns an array containing the values of the object's own properties, that is, those properties that the object itself contains, and not those that are accessible to it through a chain of prototypes.
Here's how to use it.
const person = { name: 'Fred', age: 87 }
const personValues = Object.values(person)
console.log(personValues) // ['Fred', 87]
This method also applies to arrays.
Object Method Object.entries ()
This method returns an array, each element of which is also an array containing, in format
[key, value]
, keys and values of the object's own properties.const person = { name: 'Fred', age: 87 }
const personValues = Object.entries(person)
console.log(personValues) // [['name', 'Fred'], ['age', 87]]
When applying this method to arrays, the indexes of elements are displayed as keys, and what is stored in the array at the corresponding indices is displayed as values.
Get Method getOwnPropertyDescriptors ()
This method returns information about all the properties of an object. Associated with attributes of objects are sets of attributes (descriptors). In particular, we are talking about the following attributes:
value
- the value of the object property.writable
- containstrue
if the property can be changed.get
- contains the getter function associated with the property, or if there is no such function -undefined
.set
- contains the setter function for the property orundefined
.configurable
- if there isfalse
- the property cannot be deleted, its attributes cannot be changed except for the value.enumerable
- if this property contains true -свойство
is enumerable.
Here is how to use this method.
Object.getOwnPropertyDescriptors(obj)
It takes an object whose property information you want to know, and returns an object containing this information.
const person = { name: 'Fred', age: 87 }
const propDescr = Object.getOwnPropertyDescriptors(person)
console.log(propDescr)
/*
{ name:
{ value: 'Fred',
writable: true,
enumerable: true,
configurable: true },
age:
{ value: 87,
writable: true,
enumerable: true,
configurable: true } }
*/
Why do you need this method? The fact is that it allows you to create small copies of objects, copying, among other properties, getters and setters. This could not be done using the method for copying objects
Object.assign()
, which appeared in the ES6 standard. In the following example, there is an object with a setter that outputs, using
console.log()
what is being written to its corresponding property.const person1 = {
set name(newName) {
console.log(newName)
}
}
person1.name = 'x'// x
Let's try to copy this object using the method
assign()
.const person2 = {}
Object.assign(person2, person1)
person2.name = 'x'// в консоль ничего не попадает, сеттер не скопирован
As you can see, this approach does not work. The property
name
that was a setter in the original object is now represented as a regular property. Now let's copy the object using the methods
Object.defineProperties()
(it appeared in ES5.1) and Object.getOwnPropertyDescriptors()
.const person3 = {}
Object.defineProperties(person3,
Object.getOwnPropertyDescriptors(person1))
person3.name = 'x'//x
Here in the copy of the object the setter remained.
It should be noted that the limitations characteristic of
Object.assign()
are also characteristic of the method Object.create()
when it is used for cloning objects.▍Completed commas in function parameters
This feature allows you to leave a comma at the end of the list of parameters or arguments, respectively, when you declare and when you call functions.
const doSomething = (
var1,
var2,
) => {
//...
}
doSomething(
'test1',
'test2',
)
This improves the usability of version control systems. Namely, we are talking about the fact that, when adding new parameters to a function, it is not necessary to change the existing code just to insert a comma.
▍ Asynchronous functions
The ES2017 standard introduced a design
async/await
that can be considered the most important innovation of this version of the language. Asynchronous functions are a combination of promises and generators, they simplify constructions, for which a large amount of template code and inconvenient promises chains were required to describe them. In fact, this is a high-level abstraction over promises.
When promises appeared in the ES2015 standard, they were designed to solve existing problems with asynchronous code, which they did. But in the two years that have shared the ES2015 and ES2017 standards, it has become clear that promises cannot be considered the final solution to these problems.
In particular, promises were aimed at solving the problem of “hell callbacks”, but, having solved this problem, they showed themselves not with the best hand due to the complication of the code in which they are used. As a matter of fact, the design
async/await
solves the problem of promises and increases the convenience of working with asynchronous code. Consider an example.
functiondoSomethingAsync() {
returnnewPromise((resolve) => {
setTimeout(() => resolve('I did something'), 3000)
})
}
asyncfunctiondoSomething() {
console.log(await doSomethingAsync())
}
console.log('Before')
doSomething()
console.log('After')
This code will display the following in the console.
Before
After
I did something
As you can see, after the call, the
doSomething()
program continues to run, after Before
it is output to the console After
, and after three seconds have passed, it is displayed I did something
.Asynchronous function sequential call
If necessary, asynchronous functions can form something like call chains. Such constructions have better readability than something similar, based solely on promises. This can be seen in the following example.
functionpromiseToDoSomething() {
returnnewPromise((resolve)=>{
setTimeout(() => resolve('I did something'), 10000)
})
}
asyncfunctionwatchOverSomeoneDoingSomething() {
const something = await promiseToDoSomething()
return something + ' and I watched'
}
asyncfunctionwatchOverSomeoneWatchingSomeoneDoingSomething() {
const something = await watchOverSomeoneDoingSomething()
return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => {
console.log(res) // I did something and I watched and I watched as well
})
▍Shared memory and atomic operations
Here we are talking about the SharedArrayBuffer object , which allows us to describe shared memory areas, and the Atomics object , which contains a set of atomic operations in the form of static methods. Details about the possibilities that these objects give to the programmer can be found here .
ES9 standard
ES9 (ES2018) is the latest version of the standard at the time of publication of this material. Here are its main features:
- Application of spread and rest operators to objects.
- Asynchronous iterators.
- Method
Promise.prototype.finally()
. - Regular Expression Improvements
▍Application of spread and rest operators to objects
We have already spoken about the rest and spread operators that appeared in ES6 and can be used to work with arrays. Both of them look like three points. The rest operator, in the following example of destructuring an array, allows you to place its first and second elements into constants
first
and second
, and all the others into a constant others
.const numbers = [1, 2, 3, 4, 5]
const [first, second, ...others] = numbers
console.log(first) //1console.log(second) //2console.log(others) //[ 3, 4, 5 ]
The operator
spread
allows you to pass arrays to functions that expect normal parameter lists.const numbers = [1, 2, 3, 4, 5]
const sum = (a, b, c, d, e) => a + b + c + d + e
const res = sum(...numbers)
console.log(res) //15
Now, using the same approach, you can work with objects. Here is an example of using the rest operator in a destructive assignment operation.
const { first, second, ...others } =
{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
console.log(first) //1console.log(second) //2console.log(others) //{ third: 3, fourth: 4, fifth: 5 }
Here is the spread operator used when creating a new object based on an existing one. This example continues the previous one.
const items = { first, second, ...others }
console.log(items) //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
▍ Asynchronous iterators
The new design
for-await-of
allows you to call asynchronous functions that return promises in cycles. Such cycles are waiting for promise resolution before proceeding to the next step. Here's what it looks like.forawait (const line of readLines(filePath)) {
console.log(line)
}
It should be noted that such cycles should be used in asynchronous functions - just as it is done when working with a design
async/await
.Prom Method Promise.prototype.finally ()
If the promise is successfully resolved, the next method is called
then()
. If something goes wrong, the method is called catch()
. The method finally()
allows you to perform a certain code, regardless of what happened before.fetch('file.json')
.then(data => data.json())
.catch(error =>console.error(error))
.finally(() =>console.log('finished'))
Регуляр Improved regular expressions
In regular expressions, it was possible to retrospectively check strings (
?<=
). This allows you to search in the lines for some constructions, in front of which there are some other constructions. The possibility of advanced checks using a construct
?=
was available in regular expressions implemented in JavaScript and up to the ES2018 standard. Such checks let you know if another fragment follows a fragment of a string.const r = /Roger(?= Waters)/const res1 = r.test('Roger is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //falseconsole.log(res2) //true
The construction
?!
performs the inverse operation - a match will be found only if there is no other line following the specified string.const r = /Roger(?! Waters)/gconst res1 = r.test('Roger is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //trueconsole.log(res2) //false
In retrospective verification, as already mentioned, the construction is used
?<=
.const r = /(?<=Roger) Waters/const res1 = r.test('Pink Waters is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //falseconsole.log(res2) //true
The inverse operation described can be performed with the help of the construction
?<!
.const r = /(?<!Roger) Waters/const res1 = r.test('Pink Waters is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //trueconsole.log(res2) //false
Regular Expression Unicode Control Sequences
In regular expressions, you can use a class
\d
that matches any digit, a class \s
that matches any space character, a class \w
that matches any alphanumeric character, and so on. The feature in question extends the set of classes that can be used in regular expressions, allowing you to work with Unicode sequences. We are talking about the class \p{}
and the opposite of his class \P{}
. In Unicode, each character has a set of properties. These properties are specified in curly brackets of the group
\p{}
. So, for example, a property Script
defines a family of languages to which a symbol belongs, a property ASCII
, a logical one, takes the valuetrue
for ASCII characters, and so on. For example, find out if certain strings contain exclusively ASCII characters.console.log(r.test('abc')) //trueconsole.log(r.test('ABC@')) //trueconsole.log(r.test('ABCЖ')) //false
The property
ASCII_Hex_Digit
accepts value true
only for characters that can be used to write hexadecimal numbers.const r = /^\p{ASCII_Hex_Digit}+$/uconsole.log(r.test('0123456789ABCDEF')) //trueconsole.log(r.test('H')) //false
There are many other similar properties that are used the same way as described above. Among them -
Uppercase
, Lowercase
, White_Space
, Alphabetic
, Emoji
. Here, for example, how to use the property to
Script
determine which alphabet is used in a string. Here we check the string for the use of the Greek alphabet.const r = /^\p{Script=Greek}+$/uconsole.log(r.test('ελληνικά')) //trueconsole.log(r.test('hey')) //false
Details on these properties can be read here .
Named groups
Captured character groups in ES2018 can be given names. Here's what it looks like.
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/const result = re.exec('2015-01-02')
console.log(result)
/*
[ '2015-01-02',
'2015',
'01',
'02',
index: 0,
input: '2015-01-02',
groups: { year: '2015', month: '01', day: '02' } ]
*/
Without the use of named groups, the same data would be available only as elements of an array.
const re = /(\d{4})-(\d{2})-(\d{2})/const result = re.exec('2015-01-02')
console.log(result)
/*
[ '2015-01-02',
'2015',
'01',
'02',
index: 0,
input: '2015-01-02',
groups: undefined ]
*/
Regular expression flag s
The use of the flag
s
leads to the fact that the symbol .
(dot) will, among others, correspond to the new line character. Without the use of this flag, a dot matches any character except a newline character.console.log(/hi.welcome/.test('hi\nwelcome')) // falseconsole.log(/hi.welcome/s.test('hi\nwelcome')) // true
Results
With this material, we complete the publication of translations of this JavaScript guide. Hopefully, these publications have helped those who have not worked with JavaScript before, to take their first steps in programming in this language.
Dear readers! If you have not written in JS before and mastered this language in this manual, please share your impressions.