JavaScript Guide, Part 8: ES6 Standard Feature Overview

Original author: Flavio Copes
  • Transfer
  • Tutorial
Today, in the eighth part of the translation of the JavaScript manual, we will review the features of the language that appeared in it after the release of the ES6 standard. We, in one way or another, have come across many of these opportunities before, somewhere dwelling on them in more detail, somewhere taking for granted. This section of the guide is intended, along with the disclosure of some topics that we have not previously dealt with, to streamline the knowledge of the novice developer in the field of modern JavaScript.

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: a review of the capabilities of the ES7, ES8 and ES9 standards



About ES6 standard


The ES6 standard, which it would be more correct to call ES2015 or ECMAScript 2015 (these are its official names, although everyone calls it ES6), appeared 4 years after the release of the previous standard - ES5.1. The development of all that is included in the standard ES5.1, took about ten years. Nowadays, everything that has appeared in this standard has become the familiar tools of a JS developer. It should be noted that ES6 made the most serious changes in the language (maintaining backward compatibility with its previous versions). In order to assess the scale of these changes, it can be noted that the size of the document describing the ES5 standard is approximately 250 pages, and the ES6 standard is described in a document consisting of approximately 600 pages already.

The list of the most important innovations of the ES2015 standard can include the following:

  • Arrow functions
  • Promises
  • Generators
  • Keywords letandconst
  • Classes
  • Modules
  • Pattern Literal Support
  • Support for default function parameters
  • Spread operator
  • Destructuring assignment
  • Empowering Object Literals
  • Cycle for...of
  • Support data structures MapandSet

Consider these possibilities.

Arrow functions


Arrow functions have changed the look and feel of JavaScript code. In terms of appearance, their use makes function declarations shorter and easier. Here is the usual function declaration.

const foo = functionfoo() {
  //...
}

But almost the same (although not completely similar to the above) switch function.

const foo = () => {
  //...
}

If the body of the arrow function consists of only one line, the result of which you need to return from this function, then it is written even shorter.

const foo = () => doSomething()

If the switch function takes only one parameter, you can write it as follows.

const foo = param => doSomething(param)

It should be noted that with the advent of switch functions, the usual functions have not gone away, they can still be used in the code, they work the same way as before.

Features of this keyword in switch functions


The switch functions do not have an eigenvalue this; they inherit it from the execution context.

This eliminates the problem, which, when using ordinary functions, had to be used, to save the context, to use constructions like var that = this. However, as was shown in the previous parts of the manual, this change has a serious effect on the features of working with switch functions and on the scope of their application.

Promises


Promises allow you to get rid of a well-known problem, called “hell of callbacks,” although their use implies the use of quite complex structures. This problem was solved in the ES2017 standard with the advent of a design async/awaitthat is based on promises.

JavaScript developers used promises even before the appearance of the ES2015 standard, using various libraries (for example, jQuery, q, deferred.js, vow). This indicates the importance and relevance of this mechanism. Different libraries implement it in different ways, the emergence of a standard in this area can be considered a very positive fact.
Here is the code written using callbacks (callbacks).

setTimeout(function() {
  console.log('I promised to run after 1s')
  setTimeout(function() {
    console.log('I promised to run after 2s')
  }, 1000)
}, 1000)

Using promises, this can be rewritten as follows.

const wait = () =>newPromise((resolve, reject) => {
  setTimeout(resolve, 1000)
})
wait().then(() => {
  console.log('I promised to run after 1s')
  return wait()
})
.then(() =>console.log('I promised to run after 2s'))

Generators


Generators are special functions that can suspend their own execution and resume it. This allows, while the generator is in a standby state, to be executed by another code.

The generator independently decides that it needs to pause and allow another code, “waiting” for its turn, to execute. At the same time, the generator has the opportunity to continue its execution after that operation, the results of which it is waiting for, will be completed.

All this is done thanks to a single simple keyword yield. When this keyword occurs in the generator, its execution is suspended.
A generator can contain multiple lines with this keyword, suspending its own execution several times. Generators are announced using a design *function. This asterisk before the word functionshould not be taken for something like a pointer dereference operator used in languages ​​like C, C ++ or Go.

Generators mark the appearance of a new paradigm of programming in JavaScript. In particular, they provide the possibility of two-way data exchange between the generator and other code, allow you to create long-lived cycles whilethat do not "hang" the program.

Consider an example illustrating the features of the generators. Here is the generator itself.

function *calculator(input) {
    var doubleThat = 2 * (yield (input / 2))
    var another = yield (doubleThat)
    return (input * doubleThat * another)
}

With this command, we initialize it.

const calc = calculator(10)

Then we refer to its iterator.

calc.next()

This command starts an iterator, it returns such an object.

{
  done: false
  value: 5
}

Here is the following. The code executes a function using the value inputpassed to the generator constructor. The generator code is executed until a keyword is encountered in it yield. At this moment, it returns the result of dividing inputby 2, which, since it inputis equal 10, gives a number 5. We get this number thanks to the iterator, and, along with it, an indication that the generator is not completed yet (the property donein the object returned by the iterator is set to a value false), that is, the function is only suspended.
The next time we call the iterator, we pass a number to the generator 7.

calc.next(7)

In response, the iterator returns the following object.

{
  done: false
  value: 14
}

Here the number 7was used to calculate the value doubleThat.

At first glance it may seem that the code input / 2is something like an argument of some function, but this is only the value returned in the first iteration. Here we skip this value and use the new input value 7, multiplying it by 2. After that we reach the second keyword yield, as a result the value obtained at the second iteration is equal 14.

At the next iteration, which is the last, we pass a number to the generator 100.

calc.next(100)

In response, we get the following object.

{
  done: true
  value: 14000
}

The iteration is completed (the keyword no longer occurs in the generator yield), the object returns the result of evaluating the expression (input * doubleThat * another), that is, 10 * 14 * 100an indication of the iterator’s completion ( done: true).

Let and const keywords


JavaScript always used a keyword to declare variables var. Such variables have a functional scope. Keywords letand constallow, respectively, to declare variables and constants with block scope.

This means that, for example, a variable declared using a keyword letin a loop, inside a block, ifor inside a normal block of code limited by curly brackets will not be outside this block. Variables declared with the help of varsuch blocks are not held, becoming available in the function at the level of which they are declared.

The keyword constworks in the same way as let, but with its help it declares constants that are immutable.

In modern JS code, the keyword varis rarely used. It gave way to keywords letand const. At the same time, which may seem unusual, the keyword is constused today quite widely, which indicates the popularity of the ideas of the immutability of entities in modern programming.

Classes


It happened so that JavaScript was the only extremely widespread language using the prototype inheritance model. Programmers switching to JS from languages ​​that implement a class-based inheritance mechanism felt uncomfortable in such an environment. The ES2015 standard has introduced class support in JavaScript. This is, in fact, “syntactic sugar” around JS internal mechanisms using prototypes. However, this affects the way JS applications are written.

Now JavaScript's inheritance mechanisms look like similar mechanisms in other object-oriented languages.

classPerson{
  constructor(name) {
    this.name = name
  }
  hello() {
    return'Hello, I am ' + this.name + '.'
  }
}
classActorextendsPerson{
  hello() {
    returnsuper.hello() + ' I am an actor.'
  }
}
var tomCruise = new Actor('Tom Cruise')
console.log(tomCruise.hello()) 

This program displays text to the console Hello, I am Tom Cruise. I am an actor.
In JS classes, instance variables cannot be declared; they must be initialized in constructors.

КлассаConstructor class


Classes have a special method, constructorwhich is called when creating an instance of a class using a keyword new.

SuperSword keyword super


The keyword superallows you to access the parent class from descendant classes.

▍Getters and setters


The getter for a property can be set as follows.

classPerson{
  get fullName() {
    return`${this.firstName}${this.lastName}`
  }
}

The setter can be described as shown below.

classPerson{
  set age(years) {
    this.theAge = years
  }
}

With getters and setters, they work as if they are not functions, but ordinary properties of objects.

Modules


Before the advent of the ES2015 standard, there were several competing approaches to working with modules. In particular, we are talking about the technologies RequireJS and CommonJS. This situation led to controversy in the community of JS-developers.

Nowadays, thanks to the standardization of modules in ES2015, the situation is gradually normalizing.

Модулей Import modules


Modules are imported using a view design import...from.... Here are some examples.

import * as something from'mymodule'import React from'react'import { React, Component } from'react'import React as MyLibrary from'react'

▍ Export of modules


The internal mechanisms of the module are closed from the outside world, but from the module you can export everything that it can offer to other modules. This is done using the keyword export.

exportvar foo = 2exportfunctionbar() { /* ... */ }

▍Template Literals


Sample literals are a new way to describe strings in JavaScript. Here's what it looks like.

const aString = `A string`

In addition, using the syntax of template literals allows you to embed expressions in strings, interpolate them. This is done using the view design ${a_variable}. Here is a simple example of its use:

const v = 'test'const str = `something ${v}`//something test

Here is an example more complicated, illustrating the possibility of calculating any expressions and substituting their results into a string.

const str = `something ${1 + 2 + 3}`const str2 = `something ${foo() ? 'x' : 'y' }`

Using template literals makes it much easier to declare multi-line strings.

const str3 = `Hey
this
string
is awesome!`

Compare this with what you had to do to describe multi-line strings while using the features available in the language before ES2015.

var str = 'One\n' +
'Two\n' +
'Three'

Default Function Parameters


Functions now support default parameters, in that case when corresponding arguments are not passed to them when calling functions.

const foo = function(index = 0, testing = true) { /* ... */ }
foo()

Spread operator


The spread operator (extension operator) allows you to "expand" arrays, objects or strings. This operator looks like three dots ( ...). First, consider it on the example of an array.

const a = [1, 2, 3]

Here's how to create a new array based on this array.

const b = [...a, 4, 5, 6]

Here's how to create a copy of the array.

const c = [...a]

This operator works with objects. For example - here’s how to use it to clone an object.

const newObj = { ...oldObj }

By applying the spread operator to a string, you can convert it into an array, each element of which contains one character from this string.

const hey = 'hey'const arrayized = [...hey] // ['h', 'e', 'y']

This operator, in addition to the above-described options for its use, is convenient to use when calling functions that expect a normal list of arguments, passing an array with these arguments to them.

const f = (foo, bar) => {}
const a = [1, 2]
f(...a)

Previously, this was done using a view construct f.apply(null, a), but such code is more difficult to write, and it is worse read.

Destructuring assignment


The destructive assignment technique allows, for example, to take an object, extract some values ​​from it, and put them into named variables or constants.

const person = {
  firstName: 'Tom',
  lastName: 'Cruise',
  actor: true,
  age: 54,
}
const {firstName: name, age} = person

Here properties firstNameand are extracted from the object age. The property is agewritten into a constant declared here with the same name, and the property firstName, after extraction, falls into a constant name.

Destructuring assignment is also suitable for working with arrays.

const a = [1,2,3,4,5]
const [first, second, , , fifth] = a

In the constants first, secondand fifthfall, respectively, the first, second and fifth elements of the array.

Empowering Object Literals


In ES2015, features for describing objects using object literals are greatly expanded.

▍Simplification of inclusion in variable objects


Previously, to assign any variable to the property of an object, you had to use the following construction.

const something = 'y'const x = {
  something: something
}

Now the same can be done like this.

const something = 'y'const x = {
  something
}

РотPrototypes


The prototype object can now be defined using the following construct.

const anObject = { y: 'y' }
const x = {
  __proto__: anObject
}

SuperSword keyword super


Using the keyword, superobjects can refer to prototype objects. For example, to call their methods that have the same names as the methods of these objects themselves.

const anObject = { y: 'y', test: () =>'zoo' }
const x = {
  __proto__: anObject,
  test() {
    returnsuper.test() + 'x'
  }
}
x.test() //zoox

▍Calculated property names


Calculated property names are formed during the creation of an object.

const x = {
  ['a' + '_' + 'b']: 'z'
}
x.a_b //z

Cycle for ... of


In 2009, in the ES5 standard, cycles appeared forEach(). This is a useful design, the disadvantages of which include the fact that it is very inconvenient to interrupt such cycles. A classic cycle forin situations where the execution of a cycle needs to be interrupted before its usual completion, turns out to be a much more adequate choice.

A cycle appeared in ES2015 for...of, which, on the one hand, is distinguished by its short syntax and convenience forEach, and on the other, it supports the possibility of early exit from the cycle.

Here are a couple of examples of the cycle for...of.

//перебор значений элементов массиваfor (const v of ['a', 'b', 'c']) {
  console.log(v);
}
//перебор значений элементов массива с выводом их индексов благодаря использованию метода entries()for (const [i, v] of ['a', 'b', 'c'].entries()) {
  console.log(i, v);
}

Map and Set data structures


In ES2015, data structures appeared Mapand Set(as well as their "weak" variants WeakMapand WeakSet, the use of which allows to improve the work of the "garbage collector" - the mechanism responsible for memory management in JS engines). These are very popular data structures, which, before their official implementation, had to be imitated by the available means of the language.

Results


Today we reviewed the capabilities of the ES2015 standard, which have greatly influenced the current state of the language. Our next topic will be the features of the ES2016, ES2017 and ES2018 standards.

Dear readers! What innovations of the ES6 standard seem to you the most useful?


Also popular now: