📜 ⬆️ ⬇️

ES6 humanly

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


Content






1. let, const and block scope


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:



')

2. Arrow functions


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




3. Default Settings


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 



4. Spread / Rest operator


... 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] 



5. Empowering Object Literals


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() // } 



6. Octal and Binary Literals


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 



7. Destructuring of arrays and objects


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 



8. The super keyword for objects


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(); //   ! //   ! 



9. String patterns and delimiters


ES6 provides a simpler way to insert the value of a variable or an expression result (the so-called "interpolation"), which are calculated automatically.



 let user = ''; console.log(`, ${user}!`); // , ! 



10. for ... of against for ... in



 let nicknames = ['di', 'boo', 'punkeye']; nicknames.size = 3; for (let nickname of nicknames) { console.log(nickname); } // di // boo // punkeye 


 let nicknames = ['di', 'boo', 'punkeye']; nicknames.size = 3; for (let nickname in nicknames) { console.log(nickname); } // 0 // 1 // 2 // size 



11. Map and WeakMap


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 



12. Set and WeakSet


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   



13. Classes in ES6


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:





14. Symbol data type


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)




15. Iterators


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




16. Generators


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.




17. Promises


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