ECMAscript new features

An overview of

1. Meaning of understanding

  • The relationship between language and platform
  • Systematize the need to learn ECMAscript’s advanced levels
  • The need for modern, high-quality code

2. Basic concepts

  • ES is also a scripting language, often seen as a standard specification for javascript
  • Javascript is actually an extension language of ECMAscript, which only provides the most basic syntax and does not complete the actual function development
  • Javascript implements and extends the ECMAscript standard, enabling dom and BOM manipulation in the browser, and reading and writing files in the Node environment
  • The javascript language itself is ECMAscript


Since 2015, ES has maintained an iteration of one version every year, and new features of ES have appeared successively, making javascript more and more advanced and convenient. ES2015 was only fully standardized six years after the release of ES5 and contains many disruptive new features that require further learning. From ES2015, ES does not use the version number, but use the year, such as ES2016, ES2017. ES2015, released after ES5, is also called ES6.

3.ES6

ES2015, also known as ES6, represents the new era of ECMAscript. Since then, the naming standard has also changed. Many developers use ES6 to refer to all new standards after ES5.1. For example, ES6 new specification async/await belongs to ES2017 new specification

Document address: 262.ecma-international.org/6.0/

Major changes:

  • Address the problems and shortcomings of the original syntax, such as block-level scope provided by let and cont
  • The original grammar is enhanced to make the language convenient and easy to use. Such as deconstruction, expansion, parameter defaults, template strings
  • Brand new Object, brand new function, brand new method, such as: Promise, Proxy, Object method, etc
  • New data structures, such as set, map, symbol, etc

Runtime environment

  • chrome
  • NodeJs, -v 12.13.0,
  • Nodemon tool, modify the automatic execution code,
/ / installation
npm i nodemon
/ / use:
nodemon index.js
Copy the code

2. Grammar Introduction

1. Variable declarations

Let and block-level scope

Scope: The scope within which a member of the code acts. Before ES2015, there were only function scopes and function scopes. In ES2015, block-level scopes were added. A block was a scope wrapped in {}.

if(true) {var foo = true;
}
console.log(foo) // true
if(true) {let foo = true;
}
console.log(foo) // foo is not defined
Copy the code

Problems in the loop nesting case:

for(var i=0; i<3; i++){
    for(var i=0; i<3; i++){
        console.log(i)
    }
    console.log("I after loop :" , i)
}
/ / 0
/ / 1
/ / 2
// I: 3 after the loop
Copy the code

After the inner loop completes, the inner variable I has changed and the outer variable has been overwritten, using block-level scope:

for(var i=0; i<3; i++){
    for(let i=0; i<3; i++){
        console.log(i)
    }
    console.log("I after loop :" , i)
}
/ / 0
/ / 1
/ / 2
// I: 0 after the loop
/ / 0
/ / 1
/ / 2
// I: 1 after the loop
/ / 0
/ / 1
/ / 2
// I: 2 after the loop
Copy the code

Loop to register events when accessing counters

var elements = [{}, {}, {}]
for(var i=0; i<elements.length; i++){
    elements[i].onclick = function(){
        console.log(i)
    }
}
// Closure resolution
for(var i=0; i<elements.length; i++){
    elements[i].onclick = (function(){
        return function(){
            console.log(i)
        }  
    })(i)
}
// Block-level scope resolution
for(let i=0; i<elements.length; i++){
    elements[i].onclick = function(){
        console.log(i)
    }
}
Copy the code

About the two-level scope of the for loop:

for(let i=0; i<3; i++){
    let i = 'foo'
    console.log(i)
}
// foo
// foo
// foo
Copy the code

We can see that the internally defined I variable is not affected by the loop I variable, so we can unpack the code to make it easier to understand:

let i = 0
if(i<3) {let i = 'foo'
    console.log(i)
}
i++
if(i<3) {let i = 'foo'
    console.log(i)
}
i++
if(i<3) {let i = 'foo'
    console.log(i)
}
i++
Copy the code

Inside the for loop is a two-level nested scope. Inside the body of the loop and inside the loop are two separate scopes. Let declarations do not promote variables

console.log(a);
console.log(b);
var a = 1;
let b = 2;
// undefined
// Cannot access 'b' before initialization
Copy the code

const

Const: Declares a read-only measure, constant, that cannot be modified. The memory address cannot be modified after the declaration, not the internal attributes cannot be modified

const a = 12
console.log(a)
a = 11
//Assignment to constant variable. 

const obj = {}
console.log(obj)
obj.a = 12
console.log(obj)
/ / {}
// { a: 12 }
Copy the code

Best practice: Don’t use var(use before declaration), use const (make it clear whether developers will modify), and work with let

2. Deconstruction

Destructuring, which gets a shortcut to a specified element from an array or object.

An array of deconstruction

const arr = [100.200.300.700.1000]
// The original way
const arr1 = arr[0]
const arr2 = arr[1]
const arr3 = arr[2]
/ / a new way
const [arr1, arr2, arr3] = arr
console.log(arr1, arr2, arr3)
Copy the code

Get the location member by deconstructing it

const arr = [100.200.300.700.1000]
const [ , , , arr4] = arr
console.log(arr4) / / 700
Copy the code

Add three points before deconstructing the variable name of the location to extract all elements starting at the current location

const arr = [100.200.300.700.1000]
const [arr1, , ...rest] = arr
console.log(rest) // [300, 700, 1000]
Copy the code

The length of the member in the deconstructed position is less than the length of the array to be deconstructed. The length of the member in the deconstructed position is greater than the length of the array to be deconstructed in front to back order. The deconstructed value is undefined, similar to accessing the nonexistent index of the array

const arr = [100.200]
const [foo] = arr;
console.log(foo) / / 100
const [bar, bbr, bcr] = arr
console.log(bar, bbr, bcr) // 100, 200 undefined
Copy the code

You can set default values for deconstructed location members

const arr = [100.200]
const [bar, bbr, bcr = 'default'] = arr
console.log(bar, bbr, bcr) // 100, 200 by default
Copy the code

Application scenarios

const path  = "/foo/bar/test"
const [ , rootDir] = path.split('/')
console.log(rootDir) // foo
Copy the code

Object to deconstruct

Extract based on attribute name match

const obj = {
    name: "a".age: "b"
}
const { name }  = obj
console.log(name)
Copy the code

Other features are consistent with the array, such as the unmatched member is undefined, you can set the default value. Note that since the deconstructed variable name is used to match the attribute name of the deconstructed object, a conflict occurs when the variable name has a member of the same name in scope

const obj = {
    name: "a".age: "b"
}
const name = "quanju"
const { name }  = obj
console.log(name) // Identifier 'name' has already been declared
Copy the code

This can be resolved by renaming the member name of the deconstructed location by adding a colon and the new member name.

const obj = {
    name: "a".age: "b"
}
const name = "quanju"
const { name:objName }  = obj
console.log(objName) // Identifier 'name' has already been declared
Copy the code

Application scenarios

const { log } = console
log(1)
Copy the code

3. Template string

Template string literal

ES2015 also enhances the way strings are defined. Traditionally, strings are defined in single or double quotes. ES2015 allows strings to be defined in backquotes.

const str = "hello world , my name is javascript"
const strNew = `hello world , my name is \`javascript\``

console.log(str)
console.log(strNew)

// hello world , my name is javascript
// hello world , my name is `javascript`
Copy the code

Traditional strings do not support line breaks and need to be represented by \n. Template strings support multi-line strings. Template strings support interpolation to embed corresponding values

const name = "tom"
const msg = `hey ${name}`
console.log(msg)
Copy the code

Tagged template string that can receive string data as an array

const str = console.log`hello world`
[ 'hello world' ]

const name = "tom"
const gender = true
function TagFunc (strings) {
    console.log(strings)
}
const result = TagFunc`hey, ${name} is a ${gender} `
// [ 'hey, ', ' is a ', ' ' ]
Copy the code

Tagged template string that can receive data for variables

const name = "tom"
const gender = true
function TagFunc2 (strings, name, gender) {
    console.log(strings,name, gender)
}
const result2 = TagFunc2`hey, ${name} is a ${gender} `
// [ 'hey, ', ' is a ', ' ' ] tom true
Copy the code

Tagged template string, the return value is the result of the string

const name = "tom"
const gender = true
function TagFunc3 (strings, name, gender) {
    return 123
}
const result3 = TagFunc3`hey, ${name} is a ${gender} `
console.log(result3)
/ / 123
Copy the code

Tagged template string that can process string data and return the desired string data

const name = "tom"
const gender = true
function TagFunc4 (strings, name, gender) {
    const sex = gender ? "man" : "women"
    return strings[0] + name + strings[1] + sex + strings[2]}const result4 = TagFunc4`hey, ${name} is a ${gender} `
console.log(result4)
// hey, tom is a man
Copy the code

4. String extension methods

A set of methods that determine whether a string contains a specified content

  • includes()
  • startsWith()
  • endsWidth()
const msg = 'Error: foo is not defined.'
console.log(msg.includes('foo'))
console.log(msg.startsWith('Error'))
console.log(msg.endsWith('. '))
// true
// true
// true
Copy the code

5. Function parameters

ECMAscript2015 extends a new syntax for function parameter lists

Parameter Default Value

ECMAscript2015 can be used to specify default values for function parameters in the body of the function. The default values are usually at the end of the function parameters

function foo(enable){
    enable = enable === undefined ? true : enable;
}
function foo( enable = true ){
    enable = enable === undefined ? true : enable;
}
Copy the code

The remaining parameters

For an unknown number of arguments, ECMAscript2015 can be received using the arguments pseudo-array. Operator implementation Because it receives all arguments, the operator can appear only once at the last bit of the parameter

function foo(. args){
    console.log(args)
}
foo(1.2.3.4)
// [1, 2, 3, 4]
Copy the code

6. Expand the array

. In addition to collecting rest arguments, the operator can also expand an array (spread)

const arr = ['foo'.'bar'.'dear']
console.log(
    arr[0],
    arr[1],
    arr[2],)console.log.apply(console, arr)
console.log(... arr)// foo bar dear
Copy the code

7. Arrow function

The left side of the arrow is the argument list, multiple parameters can be defined by (), the right side of the arrow is the function body, multiple expression statements need to be wrapped with {} return

function foo () {}const inf = n= > n+1
Copy the code

Arrow functions define functions in a way that makes code shorter and easier to read.

const arr = [1.2.3.5.7.11.24.9]
arr.filter(function(v){
    return v>6
})
arr.filter(v= > v>6)
Copy the code

The biggest change to the arrow function is that it does not change the this pointer

const person = {
    name: 'tom'.sayHello: function(){
        console.log(
            `hello, my name is The ${this.name}`)},sayHello2: () = > {
        console.log(
            `hello, my name is The ${this.name}`)},sayHiAsync1: function(){
        setTimeout(function(){
            console.log(this.name)
        },1000)},sayHiAsync2: function(){
        let _this = this
        setTimeout(function(){
            console.log(_this.name)
        },1000)},sayHiAsync3: function(){
        setTimeout(() = > {
            console.log(this.name)
        },1000)
    },
}
person.sayHello()
person.sayHello2()
// hello, my name is tom
// hello, my name is undefined

person.sayHiAsync1()
person.sayHiAsync2()
person.sayHiAsync3()
// undefined
// tom
// tom
Copy the code

8. Object literals are enhanced

Objects are our most commonly used data structures, and ECMAscript2015 has updated the syntax for literals. Traditional object literals require a one-to-one correspondence between property names and property values. In the new syntax, variable names can be shortened when they match property names added to the object.

const foo = "foo"
const obj = {
    bar: "bar" , / / traditional
    foo ,       // equivalent to foo: foo
}
Copy the code

Object adding method: traditional way property name colon function, new syntax, omit colon, function

const obj = {
    // The traditional way
    methods1: function(){},/ / new syntax
    methods2 () {
        // also normal function
        // This is the current object}}Copy the code

An object can use the return value of an expression as the object property name. After ECMAscript2015, dynamic values can be directly used by [], which is called calculating attribute name. The expression is wrapped with [], and the running result of the expression is used as the attribute name of the object

// The traditional way
const obj = {
    a: "11".Math.random(): 123 / / an error
}
obj[Math.random()] = 123

/ / new syntax
const obj = {
    a: "11"[Math.random()]: 123 ,/ / right
}
Copy the code

9. Object extension method

Object.assign

If the same attribute exists, the attribute in the original object overwrites the attribute of the target object from the original object to the target object. Any number of objects can be passed in. The first parameter is the target object, and the target object is returned

const source = {
    a: 12.b: 34
}
const target = {
    a: 1.c: 55
}
const result = Object.assign(target, source)
console.log(result)
console.log(result === target)

// { a: 12, c: 55, b: 34 }
// true
Copy the code

Application scenario: Copy objects

const obj1 = {name:"tom"}
function fun1(obj){
    obj.name = 'lili'
}
fun1(obj1) // { name: 'lili' }
Copy the code

In the code above, we run a function that changes the value of the property on the original object. We can avoid this problem by copying a new object

const obj2 = {name:"tom"}
function fun2(obj){
    const funobj = Object.assign({}, obj)
    funobj.name = 'lili'
}
fun2(obj2) 
console.log(obj2) // { name: 'tom' }
Copy the code

Object.is

Before ECMAscript2015, equality (==) or strict equality (===) was generally used to compare the equality of two data

console.log( 0= =false)     // true
console.log( 0= = =false)    // false
console.log( +0= = = -0 )     // true
console.log( NaN= = =NaN )   // false
Object.is(+0, -0)            // false
Object.is(NaN.NaN)          // true
Copy the code

10. Proxy object Proxy

If we want to monitor the read and write of a property of an Object, we can capture the read and write of an Object by adding properties to the Object using object.defineProperty () provided with ES5. ECMAscript2015 adds Proxy to add proxies for objects so that you can easily monitor the read and write process of objects.

const person = {
    name: "tom".age: 20
}
const personProxy = new Proxy(person, {
    get(target, property){
        console.log(target, property)
        return property in target ? target[property] : "default"
    },
    set(target, property, value){
        console.log(target, property, value)
        // Intercept to verify data
        if(property === 'age') {if(!Number.isInteger(value) ){
                throw new TypeError(`${value} is not int`)
            }
        }
        target[property] = value
    }
})
personProxy.name  // { name: 'tom', age: 20 } name
personProxy.sex  // { name: 'tom', age: 20 } sex


personProxy.age = "sss" 
// { name: 'tom', age: 20 } age sss
// sss is not int
personProxy.age = 18 
// { name: 'tom', age: 20 } age 18
Copy the code

With the Object. DefineProperty ()

  • DefineProperty can only monitor reads and writes of attributes, Proxy can monitor more operations on objects (such as delete, etc.)
const person = {
    name: "tom".age: 20
}
const personProxy = new Proxy(person, {
    deleteProperty(target, property){
        console.log(target, property)
        delete target[property]
    }
})

delete personProxy.age // name: 'tom', age: 18 } age
console.log(person)    // { name: 'tom' }
Copy the code

  • For an array operation, the defineProperty listening on an array requires overriding the array method. Proxy can listen for array changes directly
const list = []
const listProxy = new Proxy(list, {
    set(target, property, value){
        console.log(target, property, value)
        target[property] = value
        return true
    }
})
listProxy.push(100)

/ / [] 0 100
// [ 100 ] length 1
Copy the code
  • Proxy regulates the read and write of objects in a non-intrusive manner and can monitor the read and write of defined objects without doing anything to the objects themselves. DefineProperty requires us to define the attributes in the objects that need to be monitored individually in a specific way.

11.Reflect

ECMAscript2015 provides a New built-in object, which is a unified object manipulation API. Reflect is a static class, which cannot construct instance objects through New, but can only call static methods. For example, reflect.get () encapsulates a series of low-level operations on objects. It encapsulates 13 methods in total. It is the default implementation of Proxy methods for handling objects. The internal method implements the default logic as the method in the Reflect object.

const obj = {
    name: "tom".age: 14
}
const ProxyObj = new Proxy(obj, {
    get (target, property){
        return Reflect.get(target, property)
    }
})
Copy the code

For Object operations, we can use the methods above Object, or delete, in and other operators. Reflect unified Object operation mode.

const obj = {
    name: "tom".age: 14
}
// Check whether the attribute exists
'name' in obj
Reflect.has("name")
// Delete attributes
delete obj.name
Reflect.deleteProperty("name")
// Get the attributes of the object
Object.keys(obj)
Reflect.ownKeys("name")
Copy the code

12.Promise

A new asynchronous programming solution, chain calls, solves the problem of too many nested callback functions. See asynchronous programming in Javascript for details.

13. Class class

The basic use

Prior to ECMAscript2015, javascript implemented types by defining functions and their prototype objects.

// Define a function as a constructor
function Person () {
    // Access the current instance object through this
    this.name = name; 
}
// Share member methods with prototype
Person.prototype.say(){
    console.log(this.name )
}
Copy the code

After ECMAscript2015, the class keyword is used to independently define the type.

class Person {
    // constructor
    constructor(name){
        this.name = name
    }
    // Define instance methods directly
    say () {
       console.log(this.name ) 
    }
}
// Use the new keyword to create an instance
const p = new Person('aa')
p.say()
Copy the code

Methods in a class

Methods in a class are divided into static methods and instance methods. Instance methods are static methods that can be invoked directly from the type itself through instance objects constructed by the class. Previously we implemented static methods that mount methods directly on constructor objects. After ECMAscript2015, the static keyword is added to define static methods.

class Person {
    // constructor
    constructor(name){
        this.name = name
    }
    // Define instance methods directly
    say () {
       console.log(this.name ) 
    }
    // Static method
    static create (name) {
        return new Person(name)
    }
}
// Use the new keyword to create an instance
const p = new Person('aa')
p.say()
const p2 = Person.create('aa')
Copy the code

Note that static methods are mounted directly to the type, so this inside a static method does not point to the instance, but to the current type.

inheritance

Inheritance is a very important feature of object orientation. We can abstract the same properties between objects through inheritance. Before ECMAscript2015, the extends keyword was defined to implement inheritance

class Person {
    constructor(name){
        this.name = name
    }
    say () {
       console.log(this.name ) 
    }
    static create (name) {
        return new Person(name)
    }
}

class Students extends Person {
    constructor (name, studentId) {
        super(name) // Always point to the parent, which is equivalent to calling the parent's constructor
        this.studentId = studentId
    } 
    hello(){
        super.say();
        console.log(`my school id is The ${this.studentId}`)}}const s = new Students("bb")
s.hello()
Copy the code

14.Set data structure

ECMAscript2015 adds a new data structure for Set, which is similar to an array, except that the Set’s internal members are not allowed to duplicate. Set is a type that is constructed to hold unique data through the instance’s add method and returns the object itself, which can be called chain. Traversal through forEach or of to get the length of the set through size to determine whether there is a particular value in the set through HAS to delete the specified value, Returns true or false to clear all data using the clear method

const s = new Set(a); s.add(1);
s.add(12);
s.add(15);
s.add(17);
console.log(s)
s.forEach(i= > cosnole.log(i))
console.log(s.size)
console.log(s.has(11))
console.log(s.delete(15))
s.clear()
console.log(s)
/**
Set { 1, 12, 15, 17 }
1
12
15
17
4
false
true
Set {}
*/
Copy the code

The most common application scenario is array de-duplication.

const arr = [1.3.34.1.15.6.35.5.15]
const ss = new Set(arr)
console.log(ss)
// Set { 1, 3, 34, 15, 6, 35, 5 }
const resArr = Array.from(ss)
console.log(resArr)
/* [1, 3, 34, 15, 6, 35, 5] */
const resArr2 = [...new Set(arr)]
console.log(resArr2)
/* [1, 3, 34, 15, 6, 35, 5] */
Copy the code

15.Map data deconstruction

Map data deconstruction is similar to objects in that it is essentially a collection of key-value pairs. The keys in a normal object structure can only be strings, so there are problems when storing complex data structures.

const obj = {}
obj[true] = "value"
obj[1] = "value"
obj[{a:1}] = "value"
console.log(Object.keys(obj))
// [ '1', 'true', '[object Object]' ]
Copy the code

As you can see from the above code, the booleans, numbers, and object types we set are converted to strings. That is, if we add a key to an object that is not a string, it will be converted to a string using toString. ECMAscript2015’s Map addresses this problem. A Map is a strictly defined set of key-value pairs that Map the relationship between two arbitrary types of data. The set method is used to store data, the get method is used to obtain data, the HAS method is used to determine whether the data exists, the Claer method is used to clear all data, and the forEach method is used to traverse the data

const m = new Map(a); m.set({a:1}, false)
console.log(m)
// Map { { a: 1 } => false }
Copy the code

16.Symbol

The basic use

A new primitive data type. Before ECMAscript2015, the attribute names of objects were strings. Strings could be repeated, which would cause conflicts.

/// a.js
cache["aa"] = foo;

// b.js
cache["aa"] = 123;
Copy the code

This situation is easy to happen when we reference third-party libraries and extend third-party module objects for development. We usually avoid this problem by convention

/// a.js
cache["a_aa"] = foo;

// b.js
cache["b_aa"] = 123;
Copy the code

ECMAscript2015 provides a new data type Symbol to solve this problem.

const sm = Symbol(a);console.log(sm)  // Symbol()
console.log(typeof sm) // symbol


Copy the code

The best feature of this type is that it is unique, which means that the values we create through the Symbol function are never repeated.

const sm1 = Symbol(a);const sm2 = Symbol(a);console.log( sm1=== sm2) // false
Copy the code

For debugging purposes during development, the Symbol function allows us to pass a string as an argument to represent a description of the data

const sm3 = Symbol("sm3");
console.log(sm3)  // Symbol(sm3)
Copy the code

Since ECMAscript2015, objects can use values of type Symbol as attribute names.

const objSm = {
    [Symbol("sm3")]: 123
}
objSm[Symbol= ()]333;
objSm[Symbol= ()]322;
console.log(objSm)
// { [Symbol(sm3)]: 123, [Symbol()]: 333, [Symbol()]: 322 }
Copy the code

Symbol not only solves the problem of duplicate object names, but also implements private members of objects. Previously we represented the private members of an object by convention, such as beginning with an underscore (_a).

// a.js 
const name = Symbol(a)class Person {
    [name]: "aa".say(){}}/// b.js
const p = new Person()
p.say();
Copy the code

As shown in the above code, inside the object we can use the Symbol when creating the attribute to get the corresponding attribute member. In the external file we cannot create an identical Symbol, so we implement private member. The main function of Symbol is to add unique attributes to objects.

Matters needing attention

Uniqueness: Each call to the Symbol function yields a unique result, regardless of whether the description text we pass in is the same.

Symbol('foo') = = =Symbol('foo') // false
Copy the code

We can use a global variable or a static for method to reuse the same value globally. The for method takes a string as an argument, and the same string returns the same Symbol value. Symbol. For (“foo”) === Symbol. For (“foo”) for provides a global registry that provides a one-to-one correspondence between strings and symbols. Internal methods are automatically converted to the string.symbol. for(“true”) === symbol. for(true) Symbol objects provide built-in constants that can be used as identifiers for internal methods

const obj = {}
console.log(obj.toString())
console.log(obj.toString())
// [object Object]

const obj13 = {
    [Symbol.toStringTag]:'xxObject'
}
console.log(obj13.toString())
// [object xxObject]
Copy the code

Using Symbol as the attribute name of the Object is not available through forEach or object.keys (). Serializing objects with json.stringfy () also ignores this property. Only getOwnPropertySymbols can get all Symbol type property names.

const objSymbol = {
    Symbol() :'Symbolonly'.aa: 15
}
console.log(Object.keys(objSymbol) )// [ 'aa' ]
console.log(JSON.stringify(objSymbol)) // {"aa":15}
console.log(Object.getOwnPropertySymbols(objSymbol)) // [ Symbol() ]
Copy the code

17.for… Of circulation

Basic grammar

There are many ways to iterate over data in ECMAscript. For loops are good for iterating over normal arrays, for… The IN loop is good for traversing key and value pairs, and there are some functional traversal methods. ECMAscript2015 refers to the new traversal method as a unified way to traverse all data structures. Traversal of an array

const array = [133.345.233.445]
for(let item of array){
    console.log(item)
}
// 133, 345, 233, 445
Copy the code

You can use break to break out of a loop.

const array = [133.345.233.445]
for(let item of array){
    console.log(item)
    if(item > 200) {break}}/ / 133, 345
Copy the code

In addition to traversing arrays of objects, for of can also traverse pseudo-arrays.

function foo(){
    for(let item of arguments) {console.log(item)
    }
}
Fun('1'."22"."333") / / 1 22 333
Copy the code

Set and Map objects can also be traversed through for of

const set = new Set(["aa"."bb"."cc"])
for(let item of set){
    console.log(item)
}
Copy the code

Note that when we iterate over a Map object, we get an array of the object’s keys and values.

const map = new Map()
map.add('name'."tom")
map.add('age'."18")
for(let item of map){
    console.log(item)
}
// [ 'name', 'tom' ]
// [ 'age', '18' ]
for(let [key, value] of map){
    console.log(key, value)
}
Copy the code

Object traversal

const obj = {name: "tom".age: 18}
for(let item of obj){
    console.log(item)
}

// objet is not iterable
Copy the code

18. The iterator

Iterable interface

for… As a unified way to traverse data, we traverse common objects with an error. What is the reason for this? In ES, more and more structured data can be represented, such as Set, Map and Array. In order to provide a unified traversal method for various data structures, ES2015 provides an interface of Iterable. Interfaces can be understood as a unified specification standard. The Iterable interface is a kind of interface that can be used for… The of loop iterates over the specification of access, so that objects containing the Iterable interface can be for… Of traversal.


We continue to observe that symbol. iterator is a method, and inside symbol. iterator there is a next method.

const arr = [1.2.3]; 
const iterator = arr[Symbol.iterator]()
iterator.next();
// {value: 1, done: false}
iterator.next();
// {value: 2, done: false}
iterator.next();
// {value: 3, done: false}
iterator.next();
// {value: undefined, done: true}
Copy the code

conclusion

All can be for… Iterable contains an iterator method that returns an object with a next method. The next method can be used to iterate over the data. This is for… How the OF loop works.

implementation

for… The “of” loop calls the iterator method of the object to get an iterator that fetches all the data. Understand the for… After the working principle of of, we can understand why for… Why the of loop can be used as a unified way to traverse all data. We can mount an iterator method on an ordinary object to allow it to pass for… The of loop traverses.

const obj = {
    
    [Symbol.iterator]: function () {

        return {

            next: function(){

                return {
                    value: '123'.done: false
                }

            }

        }

    }
}
Copy the code

Three objects

Iterable: Iterable interface that specifies that there must be an iterator method inside that returns an iterator.

Iterator: An Iterator interface that must have a next method inside for iteration.

IterationResult: indicates the IterationResult interface. Value indicates the current iteration data, and done indicates whether the iteration is over

const objIterator = {
    store: ["foo"."bar"."aa"],
    
    [Symbol.iterator]: function () {
        let index = 0;
        let self = this;
        return {
            next: function(){
                let result = {
                    value: self.store[index],
                    done: index === self.store.length
                }
                index++
                return result
            }
        }
    }
}
for(let item of  objIterator){
    console.log(item)
}
// foo
// bar
// aa 
Copy the code

Iterator pattern

Let’s demonstrate the iterator pattern with an example. Cases work together to complete a task list

// aa generates a task list
const todoList = {
    life: ["Eat"."Sleep"."Beat the beans."].works: ["Chinese"."Mathematics". "English"],}// bb processes the task list data
for(let item of todoList.life){
    console.log(item)
}
for(let item of todoList.works){
    console.log(item)
}
Copy the code

As shown in the code above, when we need to cooperate to complete A task list development task, A is responsible for generating the task list and B is responsible for processing data. According to the above processing method, when the data of A changes, the data processing logic of B also needs to change. As follows:

// aa generates a task list
const todoList = {
    life: ["Eat"."Sleep"."Beat the beans."].learn: ["Chinese"."Mathematics". "English"].workes: ["Write code"],}// bb processes the task list data
for(let item of todoList.life){
    console.log(item)
}
for(let item of todoList.learn){
    console.log(item)
}
for(let item of todoList.workes){
    console.log(item)
}
Copy the code

Extremely coupled code like this makes maintenance much more difficult, and we can expose an interface to walk through the data, making the code more generic.

// aa generates a task list
const todoList = {
    life: ["Eat"."Sleep"."Beat the beans."].learn: ["Chinese"."Mathematics". "English"].workes: ["Write code"],
    each (callBack) {
        let alls = [].concat(this.life, this.learn, this.workes)
        for(let item of alls){
            callBack(item)
        }
    }

}

// bb processes the task list data
todoList.each(todo= >{
    console.log(todo)
})
Copy the code

As shown in the code above, by exposing the interface to the outside world, we reduce code duplication and make code maintenance easier. We can achieve the same functionality through iterators.

// aa generates a task list
const todoList = {
    life: ["Eat"."Sleep"."Beat the beans."].learn: ["Chinese"."Mathematics". "English"].workes: ["Write code"],
    each (callBack) {
        let alls = [].concat(this.life, this.learn, this.workes)
        for(let item of alls){
            callBack(item)
        }
    },
    [Symbol.iterator]: function(){
        let alls = [].concat(this.life, this.learn, this.workes)
        let index  = 0;
        return {
            next: function(){
                let result =  {
                    value: alls[index],
                    done:  index >= alls.length,
                }
                index++;
                return result
            }
            
        }
    }

}

// bb processes the task list data
for(let todo of todoList){
    console.log(todo)
}
Copy the code

At its core, iterators provide a unified interface for iterating through the data so that outsiders don’t need to care about the internal structure of the data. Our own each method above applies only to current data structures, while ES2015 provides iterators that are language level implemented iterator patterns that apply to any data structure, as long as we implement iterator methods internally.

19. The generator

The basic grammar

To avoid the problem of nested callback functions, generator functions have been added in ES2015.

  • Add * after the normal function keyword
  • The Generator function returns a Generator object after it runs
  • The next method is called on the Generator object and the function begins execution.
  • Used in conjunction with the yield keyword, the function execution can be paused.
  • The value after yield is used as the value for next.
function * foo (){
    console.log(111)
    yield 100
    console.log(222)
    yield 200
    console.log(333)
    yield 300
}
const generator = foo()
console.log(generator.next())
/ / 111
// { value: 100, done: false }
console.log(generator.next())
/ / 222
// { value: 200, done: false }
console.log(generator.next())
/ / 333
// { value: 300, done: false }
console.log(generator.next())
// { value: undefined, done: true }
Copy the code

Case implementation

Auto-increment ID transmitter

function * createId(){
    let id = 1;
    while(true) {yieldid++; }}const idMaker = createId();
console.log(idMaker.next().value)
console.log(idMaker.next().value)
console.log(idMaker.next().value)
Copy the code

We can implement iterator methods using generator functions

const todoList = {
    life: ["Eat"."Sleep"."Beat the beans."].learn: ["Chinese"."Mathematics". "English"].workes: ["Write code"],
    each (callBack) {
        let alls = [].concat(this.life, this.learn, this.workes)
        for(let item of alls){
            callBack(item)
        }
    },
    [Symbol.iterator]: function * (){
        let alls = [].concat(this.life, this.learn, this.workes)
        for(let item of alls){
            yield item
        }
    }

}

// bb processes the task list data
for(let todo of todoList){
    console.log(todo)
}
Copy the code

The most important function of generator functions is to solve the nesting problem of asynchronous callback functions, as detailed in the previous article on asynchronous programming in javascript.

20. ES2016 overview

The array includs

Find if the array contains a value. Returns a Boolean value. NaN can be looked up directly.

// Array.prototype.includes
const arr = ["foo".12."bar".NaN]

console.log(arrInclu.indexOf('bar'))  / / 2
console.log(arrInclu.includes('bar')) // true

console.log(arrInclu.indexOf(NaN))  // -1
console.log(arrInclu.includes(NaN)) // true
Copy the code

Array-exponential operation **

Like addition, subtraction, multiplication and division, called the operators of the language itself.

Math.power(2.4)
console.log(Math.pow(2.4)) / / 16

console.log( 2支那4 )  / / 16
Copy the code

21. ES2017 overview

Object.values

Keys returns the key of the Object as an array, and Values return the value of the Object as an array.

console.log(Object.keys({name:"li".age:12}))
// [ 'name', 'age' ]
console.log(Object.values({name:"li".age:12}))
// [ 'li', 12 ]
Copy the code

Object.entries

Converts an object to an array.

  • Go over with for of
  • Convert to ma p object
console.log(Object.entries({name:"li".age:12}))
// [ [ 'name', 'li' ], [ 'age', 12 ] ]

// for a loop
for(let [key, value] of Object.entries({name:"li".age:12{}))console.log(key, value)
}

// name li
// age 12

/ / to the map
console.log(new Map(Object.entries({name:"li".age:12})))

// Map { 'name' => 'li', 'age' => 12 }
Copy the code

Object.getOwnPropertyDescriptors

Object. Assign method is difficult to copy these attributes of the Object.

const nameObj = {
    firstName:"li".lastname:"lei".get FullName() {return this.firstName + "" + this.lastname
    }
}

Object.getOwnPropertyDescriptors(nameObj)
console.log(nameObj.FullName)
// li lei

const nameSelf = Object.assign({},nameObj)
nameSelf.firstName = "wang"
console.log(nameSelf.FullName)
// li lei

const descriptors = Object.getOwnPropertyDescriptors(nameObj)
console.log(descriptors)
/* { firstName: { value: 'li', writable: true, enumerable: true, configurable: true }, lastname: { value: 'lei', writable: true, enumerable: true, configurable: true }, FullName: { get: [Function: get FullName], set: undefined, enumerable: true, configurable: true } } */
const nameSelf2 = Object.defineProperties({}, descriptors)
nameSelf2.firstName = "wang"
console.log(nameSelf2.FullName)
// wang lei
Copy the code

PadStart, padEnd

Fills the start or end position of the target string with the given string until the specified length is reached.

const nameObj = {
    firstName: "li".lastname: "lei".age: 17.score: 99
}
for(let [key, value] of Object.entries(nameObj)){
    console.log(key, value)
}
/*
firstName li
lastname lei
age 17
score 99
*/
for(let [key, value] of Object.entries(nameObj)){
    console.log(
        `${key.padEnd(16."-")} | ${value.padStart(5."")}`)}/* firstName------- | li lastname-------- | lei age------------- | 17 score----------- | 99 */
Copy the code

Async / Await

Generator syntax sugar, completely solve the problem of asynchronous programming callback function nesting too deep. Look at asynchronous programming in javascript in detail.


(PS: notes source pull hook big front-end high salary training camp)

Note date :2021.04.01