From the translator:
I bring to your attention the translation of a brief (really brief) guide to ES6. It is possible to familiarize with the basic concepts of the standard.
In some cases, the original text was supplemented or replaced with a more suitable source. For example, part of the definition of the keyword const
is a translation of documentation from MDN .
To better understand some of the concepts (for high-quality translation), the standard description on the MDN website, the “You Don't Know JS: ES6 & Beyond” manual and the textbook by Ilya Kantor were used .
Translation posted on Gitkhab: https://github.com/etnolover/ES6-for-humans-translation . If errors are found, write, correct.
Link to the original text: https://github.com/metagrover/ES6-for-humans
Update 07/22/2016: added poll about const
let
, const
and block scopeconst
?The let
keyword allows declaring variables with a limited scope - only for the {...} block in which the declaration occurs. This is called a block scope. Instead of the var
keyword, which provides a scope within a function, the ES6 standard recommends using let
.
var a = 2; { let a = 3; console.log(a); // 3 } console.log(a); // 2
Another form of declaring a variable with block scope is the keyword const
. It is intended to declare variables (constants) whose values are read-only. This means not that the value of the constant is constant, but that the variable identifier cannot be reassigned.
Here is a simple example:
{ const ARR = [5, 6]; ARR.push(7); console.log(ARR); // [5,6,7] ARR = 10; // TypeError ARR[0] = 3; // console.log(ARR); // [3,6,7] }
What is worth remembering:
let
and const
, their behavior is different from the traditional behavior of var
and function
. Both let
and const
do not exist before their announcement ( from translator: for details, the author of the original manual refers to the Temporal Dead Zone article )let
and const
is the nearest block.const
it is recommended to use CURRENTS.const
, a value must be assigned simultaneously with the declaration of the variable.Arrow functions are abbreviated functions in ES6. The arrow function consists of a list of parameters ( ... )
, followed by the =>
sign and the function body.
// let addition = function(a, b) { return a + b; }; // let addition = (a, b) => a + b;
Note that in the example above, the function body is a brief entry that does not require an explicit indication that we want to return the result.
Here is an example using a block of curly braces:
let arr = ['apple', 'banana', 'orange']; let breakfast = arr.map(fruit => { return fruit + 's'; }); console.log(breakfast); // ['apples', 'bananas', 'oranges']
That's not all!...
Arrow functions don't just make the code shorter. They are closely related to the this
and context binding.
The behavior of the switch functions with the keyword this
is different from the behavior of ordinary functions with this
. Each function in JavaScript defines its own this
context, but inside the arrow functions the value of this
the same as the outside (the arrow functions do not have this
). Look at the following code:
function Person() { // Person() `this` . this.age = 0; setInterval(function growUp() { // `use strict`, growUp() `this` // , `this`, // Person(). this.age++; }, 1000); } var p = new Person();
In ECMAScript 3/5, this behavior can be changed by assigning this
value to another variable.
function Person() { var self = this; self.age = 0; setInterval(function growUp() { // `self`, // . self.age++; }, 1000); }
As mentioned above, inside the switch functions, the value of this
the same as outside, so the following code works as expected from it:
function Person() { this.age = 0; setInterval(() => { this.age++; // `this` person }, 1000); } var p = new Person();
Learn more about 'Lexical this' in the switch functions on the MDN website
ES6 allows you to set default parameters when declaring a function. Here is a simple example:
let getFinalPrice = (price, tax = 0.7) => price + price * tax; getFinalPrice(500); // 850, tax getFinalPrice(500, 0.2); // 600, tax - 0.2
...
operator is referred to as spread or rest, depending on how and where it is used.
When used in any iterable object (iterable), this operator "splits" ("spread") it into individual elements:
function foo(x, y, z) { console.log(x, y, z); } let arr = [1, 2, 3]; foo(...arr); // 1 2 3
Another common use of the ...
operator is to combine a set of values into one array. In this case, the operator works as "rest" ( from the translator : I did not find a suitable translation into Russian, from the example below everything will become clear)
function foo(...args) { console.log(args); } foo(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
ES6 allows object literals to be declared using a short syntax for initializing properties from variables and defining functional methods. Also, the standard provides the ability to calculate properties directly in an object literal.
function getCar(make, model, value) { return { // // , // , // make, // make: make model, // model: model value, // value: value // // ['make' + make]: true, // // `function` . // "depreciate: function() {}" : depreciate() { this.value -= 2500; } }; } let car = getCar('Kia', 'Sorento', 40000); console.log(car); // { // make: 'Kia', // model:'Sorento', // value: 40000, // makeKia: true, // depreciate: function() // }
ES6 introduces new support for octal and binary literals.
Adding to the beginning of the number 0o
or 0O
converts it into an octal number system (similarly, 0b
or 0B
converts it into a binary number system). Look at the following code:
let oValue = 0o10; console.log(oValue); // 8 let bValue = 0b10; console.log(bValue); // 2
Destructuring helps to avoid the use of auxiliary variables when interacting with objects and arrays.
function foo() { return [1, 2, 3]; } let arr = foo(); // [1,2,3] let [a, b, c] = foo(); console.log(a, b, c); // 1 2 3 function bar() { return { x: 4, y: 5, z: 6 }; } let { x: a, y: b, z: c } = bar(); console.log(a, b, c); // 4 5 6
ES6 allows you to use the super
method in (classless) objects with prototypes. Here is a simple example:
var parent = { foo() { console.log(" !"); } } var child = { foo() { super.foo(); console.log(" !"); } } Object.setPrototypeOf(child, parent); child.foo(); // ! // !
ES6 provides a simpler way to insert the value of a variable or an expression result (the so-called "interpolation"), which are calculated automatically.
${ ... }
used to calculate the value of a variable / expression. let user = ''; console.log(`, ${user}!`); // , !
for...of
used to iterate through a loop of iterable objects, for example, arrays. let nicknames = ['di', 'boo', 'punkeye']; nicknames.size = 3; for (let nickname of nicknames) { console.log(nickname); } // di // boo // punkeye
for...in
used to iterate through the loop of all the object properties available for iteration (enumerable). let nicknames = ['di', 'boo', 'punkeye']; nicknames.size = 3; for (let nickname in nicknames) { console.log(nickname); } // 0 // 1 // 2 // size
ES6 introduces new data structures - Map
and WeakMap
. In fact, we use "Map" in javascript all the time. Each object can be represented as a special case of Map
.
A classic object consists of keys (always in string form) and values, whereas in Map
any value (both objects and primitives) can be used for a key and value. Let's look at this code:
var myMap = new Map(); var keyString = "", keyObj = {}, keyFunc = function() {}; // myMap.set(keyString, ", ''"); myMap.set(keyObj, ", keyObj"); myMap.set(keyFunc, ", keyFunc"); myMap.size; // 3 // myMap.get(keyString); // ", ''" myMap.get(keyObj); // ", keyObj" myMap.get(keyFunc); // ", keyFunc"
Weakmap
WeakMap
is a Map
in which keys have unstable links, which allows not to interfere with the garbage collector to delete WeakMap
elements. This means you don’t have to worry about memory leaks.
It is worth noting that in WeakMap
, unlike Map
, each key must be an object .
For WeakMap
there are only four methods: delete()
, has()
, get()
and set(, )
.
let w = new WeakMap(); w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key var o1 = {}, o2 = function(){}, o3 = window; w.set(o1, 37); w.set(o2, "azerty"); w.set(o3, undefined); w.get(o3); // undefined, w.has(o1); // true w.delete(o1); w.has(o1); // false
Set objects are collections of unique values. Duplicate values are ignored because The collection must contain only unique values. Values can be primitives or object references.
let mySet = new Set([1, 1, 2, 2, 3, 3]); mySet.size; // 3 mySet.has(1); // true mySet.add(''); mySet.add({ a: 1, b:2 });
You can loop through Set
in a loop using forEach
or for...of
. The iteration occurs in the same order as the insert.
mySet.forEach((item) => { console.log(item); // 1 // 2 // 3 // '' // Object { a: 1, b: 2 } }); for (let value of mySet) { console.log(value); // 1 // 2 // 3 // '' // Object { a: 1, b: 2 } }
Set
also has delete()
and clear()
methods.
Weakset
Similar to WeakMap
, the WeakSet
object allows WeakSet
to store objects with unstable links in a collection. The object in WeakSet
is unique.
var ws = new WeakSet(); var obj = {}; var foo = {}; ws.add(window); ws.add(obj); ws.has(window); // true ws.has(foo); // false, foo ws.delete(window); // window ws.has(window); // false, window
In ES6 introduced a new syntax for classes. It is worth noting here that the ES6 class is not a new object-oriented model of inheritance. This is just syntactic sugar for prototype inheritance in JavaScript.
The class in ES6 is simply a new syntax for working with prototypes and constructor functions that we are used to using in ES5.
Functions written with the static
are used to declare static class properties.
class Task { constructor() { console.log(" task!"); } showId() { console.log(23); } static loadAll() { console.log(" tasks..."); } } console.log(typeof Task); // function let task = new Task(); // " task!" task.showId(); // 23 Task.loadAll(); // " tasks..."
extends and super in classes
Look at the following code:
class Car { constructor() { console.log(" "); } } class Porsche extends Car { constructor() { super(); console.log(" Porsche"); } } let c = new Porsche(); // // Porsche
In ES6, the extends
allows a descendant class to inherit from the parent class. It is important to note that the constructor of the descendant class must call super ().
Also, in the descendant class, you can call the method of the parent class with the help of super.()
.
Learn more about classes on the MDN website.
What is worth remembering:
function
keyword when defining functions within a class definition.Symbol is a unique and immutable data type introduced in ES6. The purpose of Symbol
is to create a unique identifier that cannot be accessed.
Here's how to create a Symbol
:
var sym = Symbol(" "); console.log(typeof sym); // symbol
Note that you cannot use new
with Symbol(…)
.
If Symbol
used as a property / key of an object, it is preserved in such a special way that the property will not be shown when a normal enumeration of object properties is displayed.
var o = { val: 10, [Symbol("")]: " - ", }; console.log(Object.getOwnPropertyNames(o)); // val
To retrieve the object's character properties, use Object.getOwnPropertySymbols(o)
The iterator refers to the elements of the collection one by one, at the same time preserving the memory of its current position in this collection. The iterator has a next()
method, which returns the next element in the sequence. This method returns an object with two properties: done (if the search is over) and value (value).
In ES6, there is a Symbol.iterator
method that defines an iterator for an object by default. Each time a loop is iterated over an object (for example, at the beginning of a for..of loop), its iterator method is called with no arguments, and the returned iterator is used to get the values for the iteration.
Let's look at the array that is iterable and at the iterator that the array has to handle its values:
var arr = [11,12,13]; var itr = arr[Symbol.iterator](); itr.next(); // { value: 11, done: false } itr.next(); // { value: 12, done: false } itr.next(); // { value: 13, done: false } itr.next(); // { value: undefined, done: true }
Note that you can write your own iterator through the definition of obj[Symbol.iterator]()
with the description of the object.
More about iterators:
On the MDN website
The generator functions are a new feature of ES6 that allows functions to create many values over a period of time, returning an object (called a generator) that can be iterated to emit values from a function one at a time.
The generator function returns the object to be iterated when it is called.
The generator function is written using the *
sign after the function
keyword, and the function keyword must contain the yield
keyword.
function *infiniteNumbers() { var n = 1; while (true) { yield n++; } } var numbers = infiniteNumbers(); // numbers.next(); // { value: 1, done: false } numbers.next(); // { value: 2, done: false } numbers.next(); // { value: 3, done: false }
Each time you call yield
return value becomes the next value in the sequence.
Also note that generators calculate their return values on demand, which allows them to efficiently represent sequences that are computationally expensive, or even infinite sequences.
ES6 has built-in support for promises. A promise is an object that is waiting for an asynchronous operation to be performed, after which (ie, after it has been executed), the promis takes one of two states: fulfilled (resolved) or rejected (completed with an error).
The standard way to create promises is the new Promise()
constructor, which accepts a handler with two functions as parameters. The first handler (usually referred to as resolve
) is the function to call along with the future value when it is ready; The second handler (usually referred to as reject
) is a function that is called to refuse to perform the promise if it cannot determine the future value.
var p = new Promise(function(resolve, reject) { if (/* */) { resolve(/* */); // fulfilled successfully ( ) } else { reject(/* reason */); // rejected () } });
Each promis has a then
method in which there are two callbacks. The first callback is called if the promise is successfully completed (resolved), while the second callback is called if the promise is completed with an error (rejected).
p.then((val) => console.log(" ", val), (err) => console.log(" ", err));
When returning a value from then
callback will pass the value to the next then
callback.
var hello = new Promise(function(resolve, reject) { resolve(""); }); hello.then((str) => `${str} `) .then((str) => `${str}!`) .then((str) => console.log(str)) // !
When promise returns, the successfully processed promise value will pass to the next callback, in order to effectively join them together.
This simple technique helps to avoid hell with callbacks ("callback hell").
var p = new Promise(function(resolve, reject) { resolve(1); }); var eventuallyAdd1 = (val) => { return new Promise(function(resolve, reject){ resolve(val + 1); }); } p.then(eventuallyAdd1) .then(eventuallyAdd1) .then((val) => console.log(val)) // 3
Source: https://habr.com/ru/post/305900/
All Articles