3

Preface

The full name of ES is ECMAScript, which is a standardized scripting language developed by ECMA. The ECMAScript version currently used by JavaScript is ECMA-417 . The latest information about ECMA can be viewed at ECMA news .

ECMAScript6 (2015), officially released in 2015, has become the next-generation standard for the JavaScript language. With the release of ES2015, the Standards Committee has decided to release a new version of ES every year. This article is a collection of commonly used features from ES6 to ES11, including ES12 that is still under planning. It only lists the general usage. To use new features, you need to use the latest version of bable to escape.

ECMAScript2015(ES6)

Let

Variables declared with let: 1. Does not belong to the top-level object window, 2. Repeated declarations are not allowed, 3. There is no variable promotion, 4. Temporary dead zone, 5. Block-level scope

1. The global variable declared by let is not an attribute of the global object window

let a = 5
console.log(window.a) // undefined

2. Using let to define variables is not allowed to repeat declaration

let a = 5
let a = 6
// VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared
//   at <anonymous>:1:1

3. The variable declared by let does not exist. Variable promotion

function foo() {
    console.log(a)
    let a = 5
}

foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization

4. The variable declared by let has a temporary dead zone

var a = 5
if (true) {
    a = 6
    let a
}
// Uncaught ReferenceError: Cannot access 'a' before initialization

In the above code, there is a global variable a, but let declares a local variable a in the block-level scope, which causes the latter to bind to this block-level scope. Therefore, before let declares the variable, assigning a value to a will report an error.

Sometimes the "temporary dead zone" is more hidden, such as:

function foo(b = a, a = 2) {
    console.log(a, b)
}
foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization

5. Variables declared by let have block-level scope

let actually adds block-level scope to JavaScript

{
    let a = 5
}
console.log(a) // undefined

Const

Use const-declared constants: 1. Does not belong to the top-level object window, 2. Repeated declarations are not allowed, 3. There is no variable promotion, 4. Temporary dead zone, 5. Block-level scope

1. After the variable is defined by const, it cannot be modified, and the modification of the variable will throw an exception.

const PI = 3.1415

console.log(PI)

PI = 5

console.log(PI)
// Uncaught TypeError: Assignment to constant variable.

const declared variable cannot be changed. If the declaration is a reference type, its memory address cannot be changed, but its content can be changed.

const obj = {
    name: 'wawa',
    age: 34
}
obj.school = 'imooc'
console.log(obj)
// {name: "wawa", age: 34, school: "imooc"}

obj = {name: 'xx'}
// VM109:9 Uncaught TypeError: Assignment to constant variable.

3. The value must be initialized when const is declared, otherwise an error will be reported

const PI

PI = 3.1415
// Uncaught SyntaxError: Missing initializer in const declaration

Destructuring assignment

A new variable assignment method is added in ES6: destructuring assignment. Allows to extract values from arrays and objects and assign values to variables in accordance with a certain pattern.

1. Array destructuring assignment

  • Assignment element can be any traversable object

    let [a, b, c] = "abc" // ["a", "b", "c"]
    let [one, two, three] = new Set([1, 2, 3])
  • The assigned variable can also be an attribute of the object, not limited to a simple variable.

    let user = {}
    [user.firstName, user.secondName] = 'Kobe Bryant'.split(' ')
    
    console.log(user.firstName, user.secondName) // Kobe Bryant
  • The application of destructuring assignment in the loop body can be used with entries.

    let user = {
    name: 'John',
    age: 30
    }
    
    // loop over keys-and-values
    for (let [key, value] of Object.entries(user)) {
    console.log(`${key}:${value}`) // name:John, then age:30
    }
  • You can skip the assignment element. If you want to ignore an element of the array and assign a variable, you can use a comma to handle it.

    // second element is not needed
    let [name, , title] = ['John', 'Jim', 'Sun', 'Moon']
    
    console.log( title ) // Sun
  • rest parameter

    let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]
    
    console.log(name1) // Julius
    console.log(name2) // Caesar
    
    // Note that type of `rest` is Array.
    console.log(rest[0]) // Consul
    console.log(rest[1]) // of the Roman Republic
    console.log(rest.length) // 2
  • If the content of the array is less than the number of variables, no error will be reported, and variables that are not assigned to the content will be undefined.

    let [firstName, surname] = []
    
    console.log(firstName) // undefined
    console.log(surname) // undefined

    Of course, you can also assign default values to variables to prevent undefined from appearing:

    // default values
    let [name = "Guest", surname = "Anonymous"] = ["Julius"]
    
    console.log(name)    // Julius (from array)
    console.log(surname) // Anonymous (default used)

    2. Object destructuring assignment

    In addition to destructuring assignment can be applied to Array, it can also be applied to Object. The basic syntax is as follows: let {var1, var2} = {var1:…, var2…}
    let options = {
    title: "Menu",
    width: 100,
    height: 200
    }
    
    let {title, width, height} = options
    
    console.log(title)  // Menu
    console.log(width)  // 100
    console.log(height) // 200
  • The default value can be specified during the assignment process:

    let options = {
    title: "Menu"
    }
    
    let {width = 100, height = 200, title} = options
    
    console.log(title)  // Menu
    console.log(width)  // 100
    console.log(height) // 200
  • rest operator

    let options = {
    title: "Menu",
    height: 200,
    width: 100
    }
    
    let {title, ...rest} = options
    
    // now title="Menu", rest={height: 200, width: 100}
    console.log(rest.height)  // 200
    console.log(rest.width)   // 100
  • Nested object

    If an Array or Object is more complicated, and it nests Array or Object, then as long as the assigned structure is the same as the assigned element on the right side.

    let options = {
    size: {
      width: 100,
      height: 200
    },
    items: ["Cake", "Donut"],
    extra: true    // something extra that we will not destruct
    }
    
    // destructuring assignment on multiple lines for clarity
    let {
    size: { // put size here
      width,
      height
    },
    items: [item1, item2], // assign items here
    title = 'Menu' // not present in the object (default value is used)
    } = options
    
    console.log(title)  // Menu
    console.log(width)  // 100
    console.log(height) // 200
    console.log(item1)  // Cake
    console.log(item2)  // Donut

    3. String deconstruction assignment

It can be regarded as the destructuring of an array:

let str = 'imooc'

let [a, b, c, d, e] = str

console.log(a, b, c, d, e)

Array

Many useful native APIs have been added to ES6 to facilitate developers to control Array more effectively, such as for...of, from, of, fill, find, findIndex, etc.

1. Array traversal method in ES6 for...of

for (let val of [1, 2, 3]) {
    console.log(val);
}
// 1,2,3

for...of supports break, continue, and return, so it is very close to the native for in function.

2. Array.from() will convert the array to an array

let arrLike = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3
}
let arr = Array.from(arrLike);
// ["a", "b", "c"]

3.Array.of()

The Array.of() method creates a new array instance with a variable number of parameters, regardless of the number or type of parameters.

The difference between Array.of() and the Array constructor is the handling of integer parameters: Array.of(7) creates an array with a single element of 7, while Array(7) creates an empty array of length 7 (note: this Refers to an array with 7 empty positions (empty), not an array composed of 7 undefined).

Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]

Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]

4.Array.prototype.fill()

The fill() method fills all elements in an array from the start index to the end index with a fixed value. Does not include the termination index.

let array = [1, 2, 3, 4]
array.fill(0, 1, 2)
// [1,0,3,4]

5. Array.prototype.find()

The find() method returns the value of the first element in the array that satisfies the provided test function, otherwise it returns undefined.

let array = [5, 12, 8, 130, 44];

let found = array.find(function(element) {
    return element > 10;
});

console.log(found);
// 12

6.Array.prototype.findIndex()

The findIndex() method returns the index of the first element in the array that satisfies the provided test function. Otherwise, it returns -1. In fact, this is a pair with find(), the difference is that it returns an index instead of a value.

let array = [5, 12, 8, 130, 44];

let found = array.find(function(element) {
    return element > 10;
});

console.log(found);
// 1

7. Array.prototype.copyWithin()

Inside the current array, copy the member at the specified position to another position (it will overwrite the original member), and then return to the current array. In other words, using this method will modify the current array.

let arr = [1, 2, 3, 4, 5]
console.log(arr.copyWithin(1, 3))
// [1, 4, 5, 4, 5]

Function

1. Default parameters

function foo(x, y = 'world') {
    console.log(x, y)
}
foo('hello', 0)

2.Rest parameter

function sum(...nums) {
    let num = 0
    nums.forEach(function(item) {
        num += item * 1
    })
    return num
}

console.log(sum(1, 2, 3)) // 6
console.log(sum(1, 2, 3, 4)) // 10

3. Spread operator

Spread Operator and Rest Parameter are operators with similar shapes but opposite meanings. Simply put, Rest Parameter "converges" indefinite parameters to an array, while Spread Operator "disperses" the contents of a fixed array to the corresponding parameters. Examples are as follows:

function sum(x = 1, y = 2, z = 3) {
    return x + y + z
}

console.log(sum(...[4])) // 9
console.log(sum(...[4, 5])) // 12
console.log(sum(...[4, 5, 6])) // 15

4.length attribute

After the function specifies the default value, the length attribute of the function will return the number of parameters for which the default value is not specified.

function foo(x = 1, y = 2, z = 3) {
    console.log(x, y)
}
console.log(foo.length)
// 0

5.name attribute

function foo() {}

foo.name // "foo"

6. Arrow function

1. This in the arrow function points to the object where it is defined, not the object where it is called.
2. Arrow functions cannot be used as constructors,
3. Arrow functions cannot use arguments object
  • If there is only one parameter, you can omit the parentheses. If it is greater than one parameter, remember to bring the parentheses.

    let hello = (name) => {
      console.log('say hello', name)
    }
    // 或者
    
    let hello = name => {
      console.log('say hello', name)
    }
  • If the return value is an expression, if the return value is an expression, return and () can be omitted

    let pow = x => x * x
  • If the return value is a literal object, it must be wrapped in parentheses

    let person = (name) => ({
        age: 20,
        addr: 'Beijing City'
    })

    7. Expand

    let foo = {
      name: 'es',
      say: () => {
          console.log(this.name, this)
      }
    }
    console.log(foo.say()) // undefined

    Because when the processing of this in the arrow function is defined, the point of this is the window pointed to by the outer layer of foo, and window has no name attribute, so the result is undefined.

Object

1. Concise notation of attributes

let name = 'xx'
  let age = 18
  let obj = {
      name,
      age
  }

2. Attribute name expression

  let s = 'school'
  let obj = {
      foo: 'bar',
      [s]: 'xx'
  }

3.Object.is()

Determine whether two objects are equal.

let obj1 = { // new Object()
    name: 'xx',
    age: 34
}

let obj2 = { // new Object()
    name: 'xx',
    age: 34
}
console.log(obj1 == obj2) // false

console.log(Object.is(obj1, obj2)) // false

let obj2 = obj1

console.log(Object.is(obj1, obj2)) // true

4.Object.assign()

The Object.assign() method is used to copy the values of all enumerable properties from one or more source objects to the target object, and it will return the target object.

const target = {
    a: 1,
    b: 2
}
const source = {
    b: 4,
    c: 5
}

const returnedTarget = Object.assign(target, source)

console.log(target)
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget)
// expected output: Object { a: 1, b: 4, c: 5 }

Class

1. Declaration class

class Animal {
    constructor(type) {
        this.type = type
    }
    walk() {
        console.log( `I am walking` )
    }
}
let dog = new Animal('dog')
let monkey = new Animal('monkey')

2. Setters & Getters

For the attributes in the class, you can directly define it in the constructor through this, or you can define it directly at the top level of the class:

class Animal {
    constructor(type, age) {
        this.type = type
        this._age = age
    }
    get age() {
        return this._age
    }
    set age(val) {
        this._age = val
    }
}

3. Static method

Is the mark of static in ES6 a static method? The code is as follows:

class Animal {
    constructor(type) {
        this.type = type
    }
    walk() {
        console.log( `I am walking` )
    }
    static eat() {
        console.log( `I am eating` )
    }
}

4. Inherit

class Animal {
    constructor(type) {
        this.type = type
    }
    walk() {
        console.log( `I am walking` )
    }
    static eat() {
        console.log( `I am eating` )
    }
}

class Dog extends Animal {
  constructor () {
    super('dog')
  }
  run () {
    console.log('I can run')
  }
}

Symbol

ES6 introduces a new primitive data type Symbol, which represents a unique value. It is the seventh data type of the JavaScript language. The first six are: undefined, null, Boolean, string, number, and object.
1. Statement method
let s = Symbol()

typeof s
// "symbol"

The variable s is a unique value. The result of typeof shows that s is a Symbol data type.

Since they are unique, then the two Symbol() must be unequal:

let s1 = Symbol()
let s2 = Symbol()
console.log(s1)
console.log(s2)
console.log(s1 === s2) // false

The new command cannot be used before the Symbol function, otherwise an error will be reported. This is because the generated Symbol is a primitive value, not an object. In other words, because the Symbol value is not an object, you cannot add attributes. Basically, it is a data type similar to a string.

2. Symbol.for()

Symbol.for() accepts a string as a parameter, and then searches for a Symbol value with the parameter as the name. If there is, return the Symbol value, otherwise, create a new Symbol value with the string as the name, and register it to the global.
let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1 === s2) // true

Both Symbol.for() and Symbol() will generate new Symbols. The difference between them is that the former will be registered in the global environment for search, while the latter will not. Symbol.for() will not return a new Symbol type value every time it is called, but will first check whether the given key already exists, and create a new value if it does not exist.

3. Symbol.keyFor()

The Symbol.keyFor() method returns a key of the registered Symbol type value.

const s1 = Symbol('foo')
console.log(Symbol.keyFor(s1)) // undefined

const s2 = Symbol.for('foo')
console.log(Symbol.keyFor(s2)) // foo

4. As the attribute name

Since every Symbol value is not equal, this means that Symbol value can be used as an identifier for the attribute name of an object, and it can be guaranteed that no attribute with the same name will appear. This is very useful when an object is composed of multiple modules to prevent a certain key from being overwritten or overwritten accidentally.

const stu1 = Symbol('李四')
const stu2 = Symbol('李四')
const grade = {
    [stu1]: {
        address: 'yyy',
        tel: '222'
    },
    [stu2]: {
        address: 'zzz',
        tel: '333'
    },
}
console.log(grade)
console.log(grade[stu1])
console.log(grade[stu2])

5. Attribute traversal

const sym = Symbol('imooc')
class User {
    constructor(name) {
        this.name = name
        this[sym] = 'imooc.com'
    }
    getName() {
        return this.name + this[sym]
    }
}
const user = new User('xiecheng')
console.log(user.getName())

for (let key in user) {
    console.log(key)
}

for (let key of Object.keys(user)) {
    console.log(key)
}

for (let key of Object.getOwnPropertySymbols(user)) {
    console.log(key)
}

for (let key of Reflect.ownKeys(user)) {
    console.log(key)
}

6. Eliminate the magic string

The magic string refers to a specific string or value that appears multiple times in the code and forms a strong coupling with the code. Well-styled code should try to eliminate magic strings and replace them with clear-meaning variables.

function getArea(shape) {
    let area = 0
    switch (shape) {
        case 'Triangle':
            area = 1
            break
        case 'Circle':
            area = 2
            break
    }
    return area
}
console.log(getArea('Triangle'))

In the above code, the strings Triangle and Circle are magic strings. It appears many times and forms a "strong coupling" with the code, which is not conducive to future modification and maintenance.

Using Symbol can solve this problem well:

const shapeType = {
    triangle: Symbol(),
    circle: Symbol()
}

function getArea(shape) {
    let area = 0
    switch (shape) {
        case shapeType.triangle:
            area = 1
            break
        case shapeType.circle:
            area = 2
            break
    }
    return area
}
console.log(getArea(shapeType.triangle))

Set

In JavaScript, Array or Object is usually used to store data. However, the search or statistics in the process of frequently operating data need to be implemented manually, and cannot be simply used directly. For example, how to ensure that Array is deduplicated, how to count the total number of data of Object, etc., must be manually implemented by yourself, which is not very convenient. In order to solve the above pain points in ES6, new data structures Set and Map are added, which correspond to the "set" and "dictionary" of the traditional data structure, respectively.
1. Basic syntax
  • Generate Set instance

    let s = new Set()

    You can define an empty Set instance, or you can pass in default data while instantiating.

     let s = new Set([1, 2, 3, 4])

    The initialized parameters must be traversable, which can be an array or a custom traversable data structure.

  • adding data

    s.add('hello')
    s.add('goodbye')
    
    或者
    s.add('hello').add('goodbye')

    Set data structure does not allow data duplication, so adding duplicate data is invalid

  • delete data
    There are two types of data deletion, one is to delete the specified data, and the other is to delete all data.

    // 删除指定数据
    s.delete('hello') // true
    // 删除全部数据
    s.clear()
  • Statistical data
    Set can quickly perform statistical data, such as whether data exists, the total number of data.

    // 判断是否包含数据项,返回 true 或 false
    s.has('hello') // true
    // 计算数据项总数
    s.size // 2
  • Array deduplication

    let arr = [1, 2, 3, 4, 2, 3]
    let s = new Set(arr)
    console.log(s)
  • Merge deduplication

    let arr1 = [1, 2, 3, 4]
    let arr2 = [2, 3, 4, 5, 6]
    let s = new Set([...arr1, ...arr2])
    console.log(s)
    console.log([...s])
    console.log(Array.from(s))
  • Intersection

    let s1 = new Set(arr1)
    let s2 = new Set(arr2)
    let result = new Set(arr1.filter(item => s2.has(item)))
    console.log(Array.from(result))
  • Subtraction

    let arr3 = new Set(arr1.filter(item => !s2.has(item)))
    let arr4 = new Set(arr2.filter(item => !s1.has(item)))
    console.log(arr3)
    console.log(arr4)
    console.log([...arr3, ...arr4])

    2. Traversal mode

  • keys(): Iterator that returns the key name
  • values(): a iterator that returns key values
  • entries(): Iterator that returns key-value pairs
  • forEach(): Use the callback function to traverse each member
  • for...of: each member can be traversed directly

     console.log(s.keys()) // SetIterator {"hello", "goodbye"}
    console.log(s.values()) // SetIterator {"hello", "goodbye"}
    console.log(s.entries()) // SetIterator {"hello" => "hello", "goodbye" => "goodbye"}
    s.forEach(item => {
        console.log(item) // hello // goodbye
    })
    
    for (let item of s) {
        console.log(item)
    }
    
    for (let item of s.keys()) {
        console.log(item)
    }
    
    for (let item of s.values()) {
        console.log(item)
    }
    
    for (let item of s.entries()) {
        console.log(item[0], item[1])
    }

    3.WeakSet

    The WeakSet structure is similar to Set, and it is also a collection of unique values. However, there are two differences between it and Set. The members of WeakSet can only be objects, not other types of values.
const ws = new WeakSet()
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
let ws = new WeakSet()
const obj1 = {
    name: 'imooc'
}
const obj2 = {
    age: 5
}
ws.add(obj1)
ws.add(obj2)
ws.delete(obj1)
console.log(ws)
console.log(ws.has(obj2))

WeakSet has no size property, and there is no way to traverse its members.

The objects in WeakSet are all weak references, that is, the garbage collection mechanism does not consider WeakSet's references to the object, that is, if other objects no longer reference the object, the garbage collection mechanism will automatically reclaim the memory occupied by the object. Do not consider that the object still exists in the WeakSet.

Map

ES6 provides Map data structure. It is similar to an object and is also a collection of key-value pairs, but the scope of "keys" is not limited to strings. Various types of values (including objects) can be used as keys. In other words, the Object structure provides a "string-value" correspondence, and the Map structure provides a "value-value" correspondence, which is a more complete implementation of the Hash structure. If you need a "key-value pair" data structure, Map is more suitable than Object.
1. Basic syntax
  • Instantiate

    let map = new Map([iterable])

    Iterable can be an array or other iterable objects, whose elements are key-value pairs (an array of two elements, for example: [[ 1,'one' ], [2,'two' ]]). Each key-value pair will be added to the new Map. null will be treated as undefined.

  • adding data

    let keyObj = {}
    let keyFunc = function() {}
    let keyString = 'a string'
    
    // 添加键
    map.set(keyString, "和键'a string'关联的值")
    map.set(keyObj, '和键keyObj关联的值')
    map.set(keyFunc, '和键keyFunc关联的值')
  • delete data

    // 删除指定的数据
    map.delete(keyObj)
    // 删除所有数据
    map.clear()
  • Statistical data

    // 统计所有 key-value 的总数
    console.log(map.size) //2
    // 判断是否有 key-value
    console.log(map.has(keyObj)) // true
  • Query data
    The get() method returns a specified element in a Map object

    console.log(map.get(keyObj)) // 和键keyObj关联的值

    2. Traversal method

  • keys() returns a new Iterator object. It contains the key value of each element inserted in the Map object in order
  • The values() method returns a new Iterator object. It contains the value of each element inserted into the Map object in order
  • The entries() method returns a new Iterator? object containing [key, value] pairs. The iteration order of the returned iterator is the same as the insertion order of the Map object.
  • The forEach() method will execute the callback function provided in the parameter once for each key-value pair in the Map object in the insertion order
  • for...of can traverse each member directly

    map.forEach((value, key) => console.log(value, key))
    
    for (let [key, value] of map) {
     console.log(key, value)
    }
    
    for (let key of map.keys()) {
     console.log(key)
    }
    
    for (let value of map.values()) {
     console.log(value)
    }
    
    for (let [key, value] of map.entries()) {
     console.log(key, value)
    }

    In fact, Object also stores and reads key-value pairs, so are there any other differences besides the differences we mentioned before?

  • Type of key

The key of an Object can only be a string or Symbols, but the key of a Map can be any value, including functions, objects, and basic types.

  • Key sequence

The key values in the map are ordered, but the keys added to the object are not. Therefore, when iterating over it, the Map object returns the key values in the order of insertion.

  • Statistics of key-value pairs

You can directly obtain the number of key-value pairs of a Map through the size property, while the number of key-value pairs of an Object can only be calculated manually.

  • Traversal of key-value pairs

Map can be iterated directly, while the iteration of Object needs to get its key array first, and then iterate.

  • performance

Map will have some performance advantages in scenarios involving frequent additions and deletions of key-value pairs.

3.WeekMap
The WeakMap structure is similar to the Map structure and is also used to generate a collection of key-value pairs.

// WeakMap 可以使用 set 方法添加成员
const wm1 = new WeakMap()
const key = {
    foo: 1
}
wm1.set(key, 2)
wm1.get(key) // 2

// WeakMap 也可以接受一个数组,
// 作为构造函数的参数
const k1 = [1, 2, 3]
const k2 = [4, 5, 6]
const wm2 = new WeakMap([
    [k1, 'foo'],
    [k2, 'bar']
])
wm2.get(k2) // "bar"

There are two differences between WeakMap and Map.

  • WeakMap only accepts objects as keys (except for null), and does not accept other types of values as keys.

    const map = new WeakMap()
    map.set(1, 2)
    // TypeError: 1 is not an object!
    map.set(Symbol(), 2)
    // TypeError: Invalid value used as weak map key
    map.set(null, 2)
    // TypeError: Invalid value used as weak map key
  • The object pointed to by the key name of the WeakMap is not included in the garbage collection mechanism.

    String

    1.Unicode notation

ES6 strengthens the support for Unicode, allowing the use of \uxxxx to represent a character, where xxxx represents the Unicode code point of the character.

"\u0061"
// "a"

However, this notation is limited to characters whose code points are between \u0000~\uFFFF. Characters outside this range must be represented in the form of two double bytes.

"\uD842\uDFB7"
// "𠮷"

"\u20BB7"
// " 7"

The above code indicates that if a value exceeding 0xFFFF is directly followed by \u (such as \u20BB7), JavaScript will be interpreted as \u20BB+7. Since \u20BB is a non-printable character, only a space is displayed, followed by a 7.

ES6 has made improvements to this point, as long as the code point is placed in curly brackets, the character can be interpreted correctly.

"\u{20BB7}"
// "𠮷"

With this notation, JavaScript has 6 ways to represent a character.

'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true

2. Traverser interface

ES6 adds an iterator interface to strings, see the Iterator section for details, so that strings can be traversed by for...of loops.

for (let item of 'imooc') {
    console.log(item)
}

3. Template string

  • String Literals
    This is to solve the problem of string splicing. Starting from ES6, strings can be defined in this way.

    `string text` 
    
    `string text line 1
     string text line 2`
    
    `string text ${expression} string text` 

    Here you can insert variables or expressions arbitrarily, as long as you wrap them with ${}.

  • Tag Literals
    The preceding string literal solves the problem of string splicing, and it is not possible for a string containing complex logic to be handled by simple expressions. So another solution is needed: Tag Literals, example:

    var retailPrice = 20
    var wholesalePrice = 16
    var type = 'retail'
    
    var showTxt = ''
    
    if (type === 'retail') {
      showTxt += '您此次的购买单价是:' + retailPrice
    } else {
      showTxt += '您此次的批发价是:' + wholesalePrice
    }

    Now you can define a Tag function, and then use this Tag function to act as a template engine:

    function Price(strings, type) {
      let s1 = strings[0]
      const retailPrice = 20
      const wholesalePrice = 16
      let txt = ''
      if (type === 'retail') {
          txt = `购买单价是:${retailPrice}` 
      } else {
          txt = `批发价是:${wholesalePrice}` 
      }
      return `${s1}${txt}` 
    }
    
    let showTxt = Price `您此次的${'retail'}` 
    
    console.log(showTxt) //您此次的购买单价是:20

    The strings parameter refers to the collection of strings separated by variables after the Tag function. The type parameter corresponds to the first variable. The Tag function can have multiple parameters of similar type.

4. Extension method

  • String.prototype.fromCodePoint()
    Used to return the corresponding character from the Unicode code point, and can recognize characters larger than 0xFFFF.

    // ES5
    console.log(String.fromCharCode(0x20BB7))
    // ஷ
    
    // ES6
    console.log(String.fromCodePoint(0x20BB7))
    // 𠮷
  • String.prototype.includes()
    In ES5, you can use the indexOf method to determine whether a string is contained in another string, indexOf returns the position of the subscript that appears, or -1 if it does not exist.

    const str = 'isxxx'
    
    console.log(str.indexOf('is'))

    ES6 provides the includes method to determine whether a string is contained in another string, and returns a boolean value.

    const str = 'isxxx'
    
    console.log(str.includes('xx'))
  • String.prototype.startsWith()
    Determine whether the parameter string is at the head of the original string, and return a boolean value.

    const str = 'isxxx'
    
    console.log(str.startsWith('is'))
  • String.prototype.endsWith()
    Determine whether the parameter string is at the end of the original string, and return a boolean value.

    const str = 'isxxx'
    
    console.log(str.endsWith('xxx'))
  • String.prototype.repeat()
    The repeat method returns a new string, which means repeating the original string n times.

    const str = 'isxxx'
    
    const newStr = str.repeat(10)
    
    console.log(newStr)

    RegExp

    1.y modifier
    ES6 adds the y modifier to regular expressions, called the "sticky" modifier.

The function of the y modifier is similar to that of the g modifier, and it is also a global match. The next match starts from the next position after the previous match was successful. The difference is that the g modifier as long as there is a match in the remaining positions, while the y modifier ensures that the match must start from the remaining first position, which is the meaning of "glue".

const s = 'aaa_aa_a'
const r1 = /a+/g
const r2 = /a+/y

r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]

r1.exec(s) // ["aa"]
r2.exec(s) // null

The above code has two regular expressions, one uses the g modifier and the other uses the y modifier. These two regular expressions are executed twice. When they are executed for the first time, they behave the same, and the remaining strings are all _aa_a. Since the g modifier has no position requirements, the second execution will return the result, and the y modifier requires that the match must start from the head, so null is returned.

If you change the regular expression to ensure that the head matches every time, the y modifier will return the result.

const s = 'aaa_aa_a'
const r = /a+_/y

r.exec(s) // ["aaa_"]
r.exec(s) // ["aa_"]

Use the lastIndex attribute to better illustrate the y modifier.

const regexp = /a/g

// 指定从2号位置(y)开始匹配
regexp.lastIndex = 2

// 匹配成功
const match = regexp.exec('xaya')

// 在3号位置匹配成功
console.log(match.index) // 3

// 下一次匹配从4号位开始
console.log(regexp.lastIndex) // 4

// 4号位开始匹配失败
regexp.exec('xaxa') // null

In the above code, the lastIndex attribute specifies the starting position of each search, and the g modifier starts from this position and searches backwards until a match is found.

The y modifier also complies with the lastIndex attribute, but requires that a match must be found at the position specified by lastIndex.

const regexp = /a/y

// 指定从2号位置开始匹配
regexp.lastIndex = 2

// 不是粘连,匹配失败
regexp.exec('xaya') // null

// 指定从3号位置开始匹配
regexp.lastIndex = 3

// 3号位置是粘连,匹配成功
const match = regexp.exec('xaxa')
console.log(match.index) // 3
console.log(regexp.lastIndex) // 4

Furthermore, the y modifier implies the head matching mark ^.

const reg = /b/y
reg.exec('aba')
// null
console.log(reg.lastIndex)

The sticky mode only affects two things in the regular matching process:

  • The match must start from re.lastIndex (equivalent to ^ in the regular expression)
  • If it matches, re.lastIndex will be modified (equivalent to g mode)
    2.u modifier
    ES6 adds the u modifier to regular expressions, meaning "Unicode mode", which is used to correctly handle Unicode characters larger than \uFFFF. In other words, the four-byte UTF-16 encoding will be processed correctly.

    /^\uD83D/u.test('\uD83D\uDC2A') // false
    
    /^\uD83D/.test('\uD83D\uDC2A') // true

    In the above code, \uD83D\uDC2A is a four-byte UTF-16 encoding, representing a character "🐪". However, ES5 does not support the four-byte UTF-16 encoding and will recognize it as two characters, resulting in the result of the second line of code being true. After adding the u modifier, ES6 will recognize it as a character, so the result of the first line of code is false.

Once the u modifier is added, the behavior of the following regular expressions will be modified.

  • Dot character
    The dot (.) character in regular expressions means any single character except the newline character. For Unicode characters with a code point greater than 0xFFFF, the dot character cannot be recognized, and the u modifier must be added.

    let s = '𠮷'
    
    /^.$/.test(s) // false
    
    /^.$/u.test(s) // true
  • Unicode character representation
    ES6 added the use of curly brackets to represent Unicode characters. This notation can only be recognized by adding the u modifier to the regular expression.

    /\u{61}/.test('a') // false
    
    /\u{61}/u.test('a') // true
    
    /\u{20BB7}/u.test('𠮷') // true
  • quantifier
    After using the u modifier, all quantifiers will correctly identify Unicode characters with code points greater than 0xFFFF.

    /a{2}/.test('aa') // true
    
    /a{2}/u.test('aa') // true
    
    /𠮷{2}/.test('𠮷𠮷') // false
    
    /𠮷{2}/u.test('𠮷𠮷') // true
  • Predefined mode
    The u modifier also affects the predefined mode, whether it can correctly identify Unicode characters with a code point greater than 0xFFFF.

    /^\S$/.test('𠮷') // false
    
    /^\S$/u.test('𠮷') // true

    The \S in the above code is a predefined pattern that matches all characters that are not spaces. Only by adding the u modifier, it can correctly match the Unicode characters whose code points are greater than 0xFFFF.

Using this, you can write a function that correctly returns the length of the string.

function codePointLength(text) {
    const result = text.match(/[\s\S]/gu)
    return result ? result.length : 0
}

const s = '𠮷𠮷'

s.length // 4
codePointLength(s) // 2
  • i modifier
    Some Unicode characters have different encodings, but the fonts are very similar. For example, \u004B and \u212A are both uppercase K.

    /[a-z]/i.test('\u212A') // false
    
    /[a-z]/iu.test('\u212A') // true

    In the above code, without the u modifier, the non-standard K character cannot be recognized.

    Number

    1. Binary and octal

  • How to convert decimal to binary in JS?

    const a = 5 // 101
    
    console.log(a.toString(2))
  • How to convert octal to binary?

    const b = 101
    
    console.log(parseInt(b, 2))

    ES6 provides a new way of writing binary and octal values, which are represented by prefixes 0b (or 0B) and 0o (or 0O) respectively.

    const a = 0B0101
    console.log(a)
    
    const b = 0O777
    console.log(b)

    2. New method

  • Number.isFinite()
    Used to check whether a value is finite, that is, it is not Infinity.

    Number.isFinite(15) // true
    Number.isFinite(0.8) // true
    Number.isFinite(NaN) // false
    Number.isFinite(Infinity) // false
    Number.isFinite(-Infinity) // false
    Number.isFinite('foo') // false
    Number.isFinite('15') // false
    Number.isFinite(true) // false
  • Number.isNaN()
    Used to check whether a value is NaN.

    Number.isNaN(NaN) // true
    Number.isNaN(15) // false
    Number.isNaN('15') // false
    Number.isNaN(true) // false
    Number.isNaN(9 / NaN) // true
    Number.isNaN('true' / 0) // true
    Number.isNaN('true' / 'true') // true
  • Number.parseInt()
    ES6 ported the global method parseInt() to the Number object, and the behavior remained completely unchanged. The purpose of this is to gradually reduce the overall approach and make the language gradually modular.

    // ES5的写法
    parseInt('12.34') // 12
    
    // ES6的写法
    Number.parseInt('12.34') // 12
  • Number.parseFloat()
    ES6 ported the global method parseFloat() to the Number object, and the behavior remained completely unchanged. The purpose of this is to gradually reduce the overall approach and make the language gradually modular.

    // ES5的写法
    parseFloat('123.45#') // 123.45
    
    // ES6的写法
    Number.parseFloat('123.45#') // 123.45
  • Number.isInteger()
    Used to determine whether a value is an integer.

    Number.isInteger(25) // true
    Number.isInteger(25.1) // false
    
    Number.isInteger() // false
    Number.isInteger(null) // false
    Number.isInteger('15') // false
    Number.isInteger(true) // false
  • Number.MAX_SAFE_INTEGER

    Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 // true
    
    Number.MAX_SAFE_INTEGER === 9007199254740991 // true
  • Number.MIN_SAFE_INTEGER

    Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER // true
    
    Number.MIN_SAFE_INTEGER === -9007199254740991 // true
  • Number.isSafeInteger()
    The range of integers that JavaScript can accurately represent is between -2^53 and 2^53 (excluding the two endpoints). If this range is exceeded, this value cannot be accurately represented.

    Math.pow(2, 53) // 9007199254740992
    
    Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

    3.Math extension

  • Math.trunc()
    The method is used to remove the decimal part of a number and return the integer part.

     console.log(Math.trunc(5.5)) // 5
    console.log(Math.trunc(-5.5)) // -5
    console.log(Math.trunc(true)) // 1
    console.log(Math.trunc(false)) // 0
    console.log(Math.trunc(NaN)) // NaN
    console.log(Math.trunc(undefined)) // NaN
    console.log(Math.trunc()) // NaN
  • Math.sign()
    The method is used to determine whether a number is positive, negative, or zero. For non-numeric values, it will first be converted to numeric values.

It will return five values.

  • The parameter is a positive number, return +1
  • The parameter is negative, return -1
  • The parameter is 0, return 0
  • The parameter is -0, return -0
  • Other values, return NaN

    console.log(Math.sign(5)) // 1
    console.log(Math.sign(-5)) // -1
    console.log(Math.sign(0)) // 0
    console.log(Math.sign(NaN)) // NaN
    console.log(Math.sign(true)) // 1
    console.log(Math.sign(false)) // 0
  • Math.cbrt()
    The method is used to calculate the cube root of a number.

    console.log(Math.cbrt(8)) // 2
    
    console.log(Math.cbrt('xx')) // NaN

    Proxy

    A very powerful feature added to the ES6 standard is Proxy, which can customize some common behaviors such as lookup, assignment, enumeration, function calls, etc. It can also be seen from the name Proxy that it contains the meaning of "proxy", as long as there is a "proxy" request, you can consider using Proxy to achieve it.

1. Basic syntax

let p = new Proxy(target, handler)
parametermeaningrequired
targetThe target object wrapped with Proxy (it can be any type of object, including native arrays, functions, or even another proxy)y
handlerAn object whose properties are functions that define the behavior of the agent when an operation is performedy

2. Commonly used interception operations

  • get
    Intercept the reading of object properties, such as proxy.foo and proxy['foo'].

    let arr = [7, 8, 9]
    arr = new Proxy(arr, {
      get(target, prop) {
          // console.log(target, prop)
          return prop in target ? target[prop] : 'error'
      }
    })
    console.log(arr[1])
    console.log(arr[10])
    let dict = {
      'hello': '你好',
      'world': '世界'
    }
    dict = new Proxy(dict, {
      get(target, prop) {
          return prop in target ? target[prop] : prop
      }
    })
    console.log(dict['world'])
    console.log(dict['imooc'])
  • set
    Intercept the setting of object properties, such as proxy.foo = v or proxy['foo'] = v, and return a boolean value.

    let arr = []
    arr = new Proxy(arr, {
      set(target, prop, val) {
          if (typeof val === 'number') {
              target[prop] = val
              return true
          } else {
              return false
          }
      }
    })
    arr.push(5)
    arr.push(6)
    console.log(arr[0], arr[1], arr.length)
  • has
    Intercept the operation of propKey in proxy and return a boolean value.

    let range = {
      start: 1,
      end: 5
    }
    
    range = new Proxy(range, {
      has(target, prop) {
          return prop >= target.start && prop <= target.end
      }
    })
    console.log(2 in range)
    console.log(9 in range)
  • ownKeys
    Intercept Object.getOwnPropertyNames(proxy), Object.getOwnPropertySymbols(proxy), Object.keys(proxy), for...in loop and return an array. This method returns the property names of all its own properties of the target object, and the return result of Object.keys() only includes the traversable properties of the target object itself.

    let userinfo = {
      username: 'xxx',
      age: 18,
      _password: '***'
    }
    userinfo = new Proxy(userinfo, {
      ownKeys(target) {
          return Object.keys(target).filter(key => !key.startsWith('_'))
      }
    })
    
    // for (let key in userinfo) {
    //     console.log(key)
    // }
    console.log(Object.keys(userinfo))
  • deleteProperty
    Intercept the operation of delete proxy[propKey] and return a boolean value.

    let user = {
      name: 'xxx',
      age: 18,
      _password: '***'
    }
    user = new Proxy(user, {
      get(target, prop) {
          if (prop.startsWith('_')) {
              throw new Error('不可访问')
          } else {
              return target[prop]
          }
      },
      set(target, prop, val) {
          if (prop.startsWith('_')) {
              throw new Error('不可访问')
          } else {
              target[prop] = val
              return true
          }
      },
      deleteProperty(target, prop) { // 拦截删除
          if (prop.startsWith('_')) {
              throw new Error('不可删除')
          } else {
              delete target[prop]
              return true
          }
      },
      ownKeys(target) {
          return Object.keys(target).filter(key => !key.startsWith('_'))
      }
    })
    console.log(user.age)
    console.log(user._password)
    user.age = 18
    console.log(user.age)
    try {
      user._password = 'xxx'
    } catch (e) {
      console.log(e.message)
    }
    
    try {
      // delete user.age
      delete user._password
    } catch (e) {
      console.log(e.message)
    }
    console.log(user.age)
    
    for (let key in user) {
      console.log(key)
    }
  • apply
    Intercept Proxy instance as a function call operation, such as proxy(...args), proxy.call(object, ...args), proxy.apply(...).

    let sum = (...args) => {
      let num = 0
      args.forEach(item => {
          num += item
      })
      return num
    }
    
    sum = new Proxy(sum, {
      apply(target, ctx, args) {
          return target(...args) * 2
      }
    })
    console.log(sum(1, 2))
    console.log(sum.call(null, 1, 2, 3))
    console.log(sum.apply(null, [1, 2, 3]))
  • construct
    Intercept the operation of the Proxy instance as a constructor call, such as new proxy(...args).

    let User = class {
      constructor(name) {
          this.name = name
      }
    }
    User = new Proxy(User, {
      construct(target, args, newTarget) {
          console.log('construct')
          return new target(...args)
      }
    })
    console.log(new User('imooc'))

    Reflect

    The Reflect object, like the Proxy object, is also a new API provided by ES6 for manipulating objects.

1. Design purpose

  • Put the method of Object belonging to the language on Reflect

    let obj = {}
    let newVal = ''
    Reflect.defineProperty(obj, 'name', {
      get() {
          return newVal
      },
      set(val) {
          console.log('set')
          // this.name = val
          newVal = val
      }
    })
    obj.name = 'es'
    console.log(obj.name)
  • Modify the return results of some Object methods to make them more reasonable

    // 老写法
    try {
      Object.defineProperty(target, property, attributes)
      // success
    } catch (e) {
      // failure
    }
    
    // 新写法
    if (Reflect.defineProperty(target, property, attributes)) {
      // success
    } else {
      // failure
    }
  • Let Object operations become functional behaviors

    // 老写法
    'assign' in Object // true
    
    // 新写法
    Reflect.has(Object, 'assign') // true
  • The methods of the Reflect object have a one-to-one correspondence with the methods of the Proxy object. As long as it is a method of the Proxy object, the corresponding method can be found on the Reflect object.

    Proxy(target, {
      set: function(target, name, value, receiver) {
          var success = Reflect.set(target, name, value, receiver)
          if (success) {
              console.log('property ' + name + ' on ' + target + ' set to ' + value)
          }
          return success
      }
    })

    Reflect is a built-in object that provides methods for intercepting JavaScript operations. These methods are the same as those of the processor object. Reflect is not a function object, so it is not constructible.

2. Common methods

  • Reflect.apply()

    Reflect.apply(target, thisArgument, argumentsList), target is the target function; thisArgument is the this object bound when the target function is called; argumentsList is the argument list passed in when the target function is called, the parameter should be an array-like object
Reflect.apply(Math.floor, undefined, [1.75])
// 1

Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111])
// "hello"

Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index
// 4

Reflect.apply(''.charAt, 'ponies', [3])
// "i"
  • Reflect.construct()
    The Reflect.construct() method behaves a bit like the new operator constructor, which is equivalent to running new target(...args)

    var d = Reflect.construct(Date, [1776, 6, 4])
    d instanceof Date // true
    d.getFullYear() // 1776
  • Reflect.define​Property()
    The static method Reflect.defineProperty() is basically equivalent to the Object.defineProperty() method, the only difference is that it returns a Boolean value.

    const student = {}
    Reflect.defineProperty(student, 'name', {
      value: 'Mike'
    }) // true
    student.name // "Mike"
  • Reflect.delete​Property()
    Reflect.deleteProperty allows you to delete a property on an object. Returns a Boolean value indicating whether the attribute was successfully deleted. It is almost the same as the non-strict delete operator.

    var obj = {
      x: 1,
      y: 2
    }
    Reflect.deleteProperty(obj, "x") // true
    obj // { y: 2 }
    
    var arr = [1, 2, 3, 4, 5]
    Reflect.deleteProperty(arr, "3") // true
    arr // [1, 2, 3, , 5]
    
    // 如果属性不存在,返回 true
    Reflect.deleteProperty({}, "foo") // true
    
    // 如果属性不可配置,返回 false
    Reflect.deleteProperty(Object.freeze({
      foo: 1
    }), "foo") // false
  • Reflect.get()
    The Reflect.get() method works like getting properties from object (target[propertyKey]), but it is executed as a function.

    // Object
    var obj = {
      x: 1,
      y: 2
    }
    Reflect.get(obj, 'x') // 1
    
    // Array
    Reflect.get(['zero', 'one'], 1) // "one"
    
    // Proxy with a get handler
    var x = {
      p: 1
    }
    var obj = new Proxy(x, {
      get(t, k, r) {
          return k + 'bar'
      }
    })
    Reflect.get(obj, 'foo') // "foobar"
  • Reflect.get​OwnProperty​Descriptor()
    The static method Reflect.getOwnPropertyDescriptor() is similar to the Object.getOwnPropertyDescriptor() method. If it exists in the object, it returns the attribute descriptor of the given attribute, otherwise it returns undefined.

    Reflect.getOwnPropertyDescriptor({
      x: 'hello'
    }, 'x')
    // {value: "hello", writable: true, enumerable: true, configurable: true}
    
    Reflect.getOwnPropertyDescriptor({
      x: 'hello'
    }, 'y')
    // undefined
    
    Reflect.getOwnPropertyDescriptor([], 'length')
    // {value: 0, writable: true, enumerable: false, configurable: false}
  • For more methods, please refer to Reflect

Promise

1. Basic syntax

Promise is to solve the "callback hell" problem, which can make the processing of asynchronous operations very elegant. Callback hell, the code is difficult to maintain. Often the output of the first function is the input of the second function. This phenomenon promises can support multiple concurrent requests. Obtaining data from concurrent requests. This promise can solve the asynchronous problem. Say that promises are asynchronous.

Create a Promise instance.

const promise = new Promise(function(resolve, reject) {
    // ... some code

    if ( /* 异步操作成功 */ ) {
        resolve(value)
    } else {
        reject(error)
    }
})

The Promise constructor accepts a function as a parameter, and the two parameters of the function are resolve and reject. They are two functions, provided by the JavaScript engine, so you don't need to deploy them yourself.

  • If the processing result is normal, call resolve (processing result value) to change the state of the Promise object from "unfinished" to "success" (that is, from pending to resolved), call when the asynchronous operation succeeds, and change the result of the asynchronous operation , Passed as a parameter
  • If the processing result is wrong, call reject(Error object) to change the state of the Promise object from "unfinished" to "failed" (that is, from pending to rejected), call when the asynchronous operation fails, and report the asynchronous operation Error, passed as a parameter.
    After the Promise instance is generated, you can use the then method to specify the callback functions for the resolved state and the rejected state respectively.

    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    })

    The Promise is stateful (pending, fulfilled, rejected), and the Promise object determines which method to execute based on the state. When the Promise is instantiated, the state is pending by default. When the asynchronous operation is completed, the state will be changed to fulfilled. If the asynchronous operation encounters an exception, the state will be changed to rejected.

2、Promise.prototype.then()

var promise = new Promise(function(resolve, reject) {
    resolve('传递给then的值')
})
promise.then(function(value) {
    console.log(value)
}, function(error) {
    console.error(error)
})
  • When the handler returns a normal value, this value will be passed to the onFulfilled method of the Promise object.
  • When an exception occurs in the defined handler, this value will be passed to the onRejected method of the Promise object.

3、Promise.prototype.catch()

Catching exceptions is the most basic requirement for program quality assurance. You can use the catch method of the Promise object to capture any exceptions that occur during asynchronous operations

function test() {
    return new Promise((resolve, reject) => {
        reject(new Error('es'))
    })
}

test().catch((e) => {
    console.log(e.message) // es
})

4、Promise.resolve()

Under normal circumstances, we will use new Promise() to create Promise objects, but we can also use other methods.

Here, we will learn how to use the two methods Promise.resolve and Promise.reject.

The static method Promise.resolve(value) can be thought of as a shortcut to the new Promise() method.

For example, Promise.resolve(42) can be considered as syntactic sugar for the following code.

new Promise(function(resolve) {
    resolve(42)
})

The return value of the method Promise.resolve(value) is also a Promise object, so we can make a .then call to its return value as follows.

Promise.resolve(42).then(function(value) {
    console.log(value)
})

5、Promise.reject()

Promise.reject(error) is a static method similar to Promise.resolve(value), and is a shortcut for the new Promise() method.

For example, Promise.reject(new Error("error")) is the syntactic sugar form of the following code.

new Promise(function(resolve, reject) {
    reject(new Error('出错了'))
})

The function of this code is to call the onRejected function specified by the Promise object through then, and pass the Error object to the onRejected function.

Promise.reject(new Error('BOOM!'))

6、Promise.all()

var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then(function(results) {
    console.log(results) // [1, 2, 3]
})

Promise.all generates and returns a new Promise object, so it can use all methods of the Promise instance. This method will only return when all the Promise objects in the promise array of parameter passing promises have become resolved, and the newly created Promise will use the value of these promises.

If any of the promises in the parameter is reject, the entire Promise.all call will be terminated immediately and a new promise object that is rejected will be returned.

Since each element in the parameter array is wrapped by Promise.resolve, Promise.all can handle different types of Promise objects.

7、Promise.race()

var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
Promise.race([p1, p2, p3]).then(function(value) {
    console.log(value) // 1
})

Promise.race generates and returns a new Promise object.

If any Promise object in the parameter promise array becomes resolve or reject, the function will return and use the value of this Promise object to resolve or reject.

Generator

Generators are functions that can be used to control iterators. They can be paused and then resumed at any time. If this sentence is not easy to understand, you can look at the next example.

  1. Regular loop

    for (let i = 0; i < 5; i += 1) {
     console.log(i)
    }
    // this will return immediately 0 -> 1 -> 2 -> 3 -> 4
  2. Use Generator

    function* generatorForLoop() {
     for (let i = 0; i < 5; i += 1) {
         yield console.log(i)
     }
    }
    
    const genForLoop = generatorForLoop()
    
    console.log(genForLoop.next()) // first console.log - 0
    console.log(genForLoop.next()) // 1
    console.log(genForLoop.next()) // 2
    console.log(genForLoop.next()) // 3
    console.log(genForLoop.next()) // 4

    In contrast to the code, the conventional loop can only traverse all the values at once, and the Generator can get the traversed values in turn by calling the next method, making the execution of the traversal "controllable".

1. Basic syntax

function* gen() {
    yield 1
    yield 2
    yield 3
}

let g = gen()
// "Generator { }"

This is the definition method of Generator. There are several points worth noting:

  • One more than normal function*
  • The function uses yield to control the "pause" of the execution of the program
  • The return value of the function "restores" the program execution by calling next

The definition of Generator function cannot use arrow functions, otherwise it will trigger SyntaxError

let generator = * () => {} // SyntaxError
let generator = () * => {} // SyntaxError
let generator = ( * ) => {} // SyntaxError

2, yield expression
The yield keyword is used to pause and resume a generator function

  • The return value of the yield expression is undefined, but the next method of the iterator object can modify this default value.
  • The next method of the Generator object will pause when it encounters a yield and return an object. This object includes two attributes: value and done.

     function* gen() {
        let val
        val = yield 1
        console.log( `1:${val}` ) // 1:undefined
        val = yield 2
        console.log( `2:${val}` ) // 2:undefined
        val = yield 3
        console.

蛙哇
307 声望20 粉丝