preface

ES stands for ECMAScript. ECMAScript is a standardized scripting language developed by ECMA. The current version of ECMAScript used by JavaScript is ECMA-417. The latest information about ECMA can be found in ECMA News.

ECMAScript6 (2015), officially released in 2015, has become the next generation standard for JavaScript. With the release of ES2015, the Standards Committee decided to release a new version of ES every year. This article is a collection of features commonly used in ES6 to ES11, including ES12, which is still in the planning. It only lists the general usage, and uses the latest version of Bable to escape the new features.

ECMAScript2015 (ES6)

Let

Variables declared with let: 1. Not belonging to the top-level object Window, 2. No duplicate declarations allowed,3. No variable promotion,4. Temporary dead zones,5. Block-level scope

1. The global variable declared by let is not a property of the global object Window

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

2. Using let to define variables does not allow repeated declarations

let a = 5
let a = 6
// VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared
// at 
      
       :1:1
      
Copy the code

3. Variables declared by let do not have variable promotion

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

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

4. Variables declared by let have temporary dead zones

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

In the above code, there is a global variable A, but let declared a local variable A in the block-level scope, causing the latter to bind the block-level scope. Therefore, assignment to A will report an error before let declared the variable.

Sometimes “temporary dead zones” are hidden, such as:

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

5. Variables declared by let have block-level scope

Let actually adds block-level scope to JavaScript

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

Const

Const const const const const const const const const const const const const No duplicate declarations allowed,3. No variable promotion,4. Temporary dead zones,5. Block-level scope

1. After a const variable is defined, it cannot be modified. Modifying a variable throws an exception.

const PI = 3.1415

console.log(PI)

PI = 5

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

2. A const variable cannot be changed. If a reference type is declared, its memory address cannot 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.
Copy the code

3. Const must be initialized or an error will be reported

const PI

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

Deconstruction assignment

A new method of variable assignment has been added in ES6: destruct assignment. Allows you to extract values from arrays and objects and assign values to variables in a pattern.

1. Array deconstruction assignment

  • The assignment element can be any traversable object
  let [a, b, c] = "abc" // ["a", "b", "c"]
  let [one, two, three] = new Set([1.2.3])
Copy the code
  • The assigned variable can also be a property of an object, not just a variable.
let user = {}
[user.firstName, user.secondName] = 'Kobe Bryant'.split(' ')

console.log(user.firstName, user.secondName) // Kobe Bryant
Copy the code
  • The use of deconstructed assignments in the body of a loop 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
}
Copy the code
  • You can skip the assignment element, or if you want to omit an element of the array to assign to a variable, you can use a comma.
// second element is not needed
let [name, , title] = ['John'.'Jim'.'Sun'.'Moon']

console.log( title ) // Sun
Copy the code
  • Rest parameters
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
Copy the code
  • If the contents of the array are less than the number of variables, no error is reported. Variables that are not allocated to the contents are undefined.
let [firstName, surname] = []

console.log(firstName) // undefined
console.log(surname) // undefined
Copy the code

You can also give variables default values to prevent undefined:

// default values
let [name = "Guest", surname = "Anonymous"] = ["Julius"]

console.log(name)    // Julius (from array)
console.log(surname) // Anonymous (default used)
Copy the code

2. Object deconstruction assignment

Destructuring assignments can be applied to objects as well as arrays. 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
Copy the code
  • The assignment process can specify a default value:
let options = {
  title: "Menu"
}

let {width = 100, height = 200, title} = options

console.log(title)  // Menu
console.log(width)  / / 100
console.log(height) / / 200
Copy the code
  • 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
Copy the code
  • Nested objects

    If an Array or Object is complex and has nested arrays or objects, it is fine as long as the structure assigned is the same as the element assigned to the right

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
Copy the code

3. String deconstruction assignment

Think of it as an array deconstruction:

let str = 'imooc'

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

console.log(a, b, c, d, e)
Copy the code

Array

In ES6, a number of useful native apis have been added to make it easier for developers to control arrays, such as for… Of, from, of, fill, find, findIndex, etc.

1. ES6 array traversal for… of

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

for… Of supports break, continue, and return, so it is functionally very close to native for.

2. Array.from() converts an Array to an Array

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

3.Array.of()

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

The difference between array.of () and Array constructors is that they handle integer arguments: array.of (7) creates an Array with a single element of 7, while Array(7) creates an empty Array of length 7 (note: This is an array with seven empty Spaces, not seven undefined ones.

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

Array(7); // [,,,,,,]
Array(1.2.3); / / [1, 2, 3]
Copy the code

4.Array.prototype.fill()

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

let array = [1.2.3.4]
array.fill(0.1.2)
/ /,0,3,4 [1]
Copy the code

5. Array.prototype.find()

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

let array = [5.12.8.130.44];

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

console.log(found);
/ / 12
Copy the code

6.Array.prototype.findIndex()

The findIndex() method returns the index of the first element in the array that satisfies the provided test function. Otherwise -1 is returned. This is actually a pair of find() except 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
Copy the code

7. Array.prototype.copyWithin()

Inside the current array, copies the member at the specified location to another location (overwriting the original member), and returns the current array. That is, using this method, you modify the current array.

let arr = [1.2.3.4.5]
console.log(arr.copyWithin(1.3))
// [1, 4, 5, 4, 5]
Copy the code

Function

1. Default parameters

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

2. The Rest parameters

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
Copy the code

3. Extend operators

Spread Operator and Rest Parameter are similar but opposite operators. Simply put, Rest Parameter “converges” variable parameters into an array, while Spread Operator “scatters” fixed array contents into corresponding parameters. The following is an example:

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
Copy the code

4. Length attribute

After a default value is specified, the length property of the function returns the number of arguments without a default value.

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

5. Name attribute

function foo() {}

foo.name // "foo"
Copy the code

Arrow function

1. The arrow function this refers to the object on which it was defined, not the object on which it was called.

Arrow functions cannot be used as constructors. Arrow functions cannot use arguments objects

  • If you have only one argument, omit the parentheses. If you have more than one argument, always include the parentheses.
let hello = (name) = > {
    console.log('say hello', name)
}
/ / or

let hello = name= > {
    console.log('say hello', name)
}
Copy the code
  • If the return value is an expression, you can omit return and {} if the return value is an expression.
let pow = x= > x * x
Copy the code
  • If the return value is a literal object, be sure to enclose it in parentheses
let person = (name) = > ({
      age: 20.addr: 'Beijing City'
  })
Copy the code

7. Develop

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

Because the arrow handles this by defining the window that this points to outside of foo, which has no name attribute, undefined.

Object

1. Concise representation of attributes

let name = 'xx'
  let age = 18
  let obj = {
      name,
      age
  }
Copy the code

2. Attribute name expression

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

3.Object.is()

Determines 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
Copy the code

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, which it returns.

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 }
Copy the code

Class

1. The class declaration

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

2. Setters & Getters

Attributes in a class can be defined directly from constructor via this, or directly from the top layer 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
    }
}
Copy the code

3. Static methods

In ES6, static is not 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`)}}Copy the code

4. Inheritance

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')}}Copy the code

Symbol

ES6 introduces a new primitive data type, Symbol, that represents unique values. It is the seventh data type in JavaScript, with undefined, NULL, Boolean, String, Number, and Object being the first six.

1. Declaration mode

let s = Symbol(a)typeof s
// "symbol"
Copy the code

The variable S is a unique value. The result of typeof indicates that S is the Symbol data type.

The Symbol() is not equal to the Symbol().

let s1 = Symbol(a)let s2 = Symbol(a)console.log(s1)
console.log(s2)
console.log(s1 === s2) // false
Copy the code

Do not use the new command before the Symbol function, otherwise an error will be reported. This is because the generated Symbol is a primitive type value, not an object. That is, because the Symbol value is not an object, attributes cannot be added. Basically, it’s a data type similar to a string.

2. Symbol.for()

Symbol.for() takes a string as an argument and searches for a Symbol value named for that argument. If so, return the Symbol value, otherwise create a new Symbol with the name of the string and register it globally.

let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1 === s2) // true
Copy the code

Symbol. For () and Symbol() both generate a new Symbol. The difference is that the former will be registered in the global environment for search, while the latter will not. Symbol.for() does not return a new Symbol value each time it is called. Instead, it checks to see if the given key already exists and creates a new value if it does not.

3. Symbol.keyFor()

The symbol.keyfor () method returns the key of a 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
Copy the code

4. As the attribute name

Since each Symbol value is not equal, this means that the Symbol value can be used as an identifier for the property name of the object, ensuring that no property with the same name will appear. This is useful in cases where an object is made up of multiple modules, preventing a key from being accidentally overwritten or overwritten.

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

5. Attribute traversal

const sym = Symbol('xxx')
class User {
    constructor(name) {
        this.name = name
        this[sym] = 'xxx.com'
    }
    getName() {
        return this.name + this[sym]
    }
}
const user = new User('lisi')
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)
}
Copy the code

6. Eliminate magic strings

A magic string is a specific string or number that occurs multiple times in the code and is strongly coupled to the code. Well-styled code should eliminate magic strings as much as possible and replace them with well-defined 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'))
Copy the code

In the code above, the strings Triangle and Circle are magic strings. It occurs multiple times, creating a “strong coupling” with the code that is not conducive to future modifications and maintenance.

Use Symbol to solve this problem:

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))
Copy the code

Set

In JavaScript, you usually use arrays or objects to store data. However, in the process of frequent operation of data search or statistics and need to be manually implemented, and can not be simply used directly. For example, how to ensure that the Array is de-weighted, how to count the total number of Object data, etc., must be manually implemented, which is not very convenient. In ES6, data structures Set and Map were added to address these pain points, which correspond to traditional data structures “collections” and “dictionaries” respectively.

1. Basic grammar

  • Generating a Set instance
let s = new Set(a)Copy the code

You can define an empty Set instance, or you can pass in default data along with the instantiation.

 let s = new Set([1.2.3.4])
Copy the code

The initialization parameter must be traversable, either an array or a custom traversal data structure.

  • Add data
s.add('hello')
s.add('goodbye') or s.a dd ('hello').add('goodbye')
Copy the code

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

  • Delete the data

Data can be deleted in two ways: one is to delete specified data, the other is to delete all data.

// Delete the specified data
s.delete('hello') // true
// Delete all data
s.clear()
Copy the code
  • statistics

Set can quickly perform statistics, such as the existence of data, the total number of data.

// Check whether data items are included, return true or false
s.has('hello') // true
// Count the total number of data items
s.size / / 2
Copy the code
  • Array to heavy
let arr = [1.2.3.4.2.3]
let s = new Set(arr)
console.log(s)
Copy the code
  • Merge to heavy
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))
Copy the code
  • 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))
Copy the code
  • Difference set
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])
Copy the code

2. Traversal mode

  • Keys () : returns a traverser for key names
  • Values () : Iterator that returns key values
  • Entries () : Returns a traverser for key and value pairs
  • ForEach () : Iterates through each member using the callback function
  • for… Of: traverses each member 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])}Copy the code

3.WeakSet

WeakSet structure is similar to Set, which is also a collection of non-repeating values. However, it differs from Set in two ways. WeakSet members 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
Copy the code
let ws = new WeakSet(a)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))
Copy the code

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

WeakSet objects are weak references, that is, garbage collection mechanism does not consider WeakSet’s reference to the object, that is, if other objects no longer reference the object, then garbage collection mechanism will automatically recover the memory occupied by the object, not considering the object still exists in WeakSet.

Map

ES6 provides Map data structures. It is a collection of key-value pairs similar to objects, but the range of “keys” is not limited to strings. Values of all types (including objects) can be used as keys. In other words, the Object structure provides string-value mapping, and the Map structure provides value-value mapping, which is a more complete Hash structure implementation. If you need key-value data structures, Map is better than Object.

1. Basic grammar

  • instantiation
let map = new Map([iterable])
Copy the code

Iterable can be an array or any other Iterable object whose elements are key-value pairs (an array of two elements, for example: [[1, ‘one’], [2, ‘two’]]). Each key-value pair is added to the new Map. Null will be treated as undefined.

  • Add data
let keyObj = {}
let keyFunc = function() {}
let keyString = 'a string'

/ / add the key
map.set(keyString, "Value associated with key 'a string'")
map.set(keyObj, 'Value associated with keyObj')
map.set(keyFunc, 'Value associated with keyFunc')
Copy the code
  • Delete the data
// Delete the specified data
map.delete(keyObj)
// Delete all data
map.clear()
Copy the code
  • statistics
// Count the total number of key-values
console.log(map.size) / / 2
// Check whether there is a key-value
console.log(map.has(keyObj)) // true
Copy the code
  • Query data

The get() method returns a specified element in a Map object

console.log(map.get(keyObj)) // The value associated with keyObj
Copy the code

2. Traversal mode

  • Keys () returns a new Iterator object. It contains the keys that are inserted sequentially for each element in the Map object
  • The values() method returns a new Iterator. It contains values that are inserted sequentially for each element in the Map object
  • The entries() method returns a new Iterator containing the [key, value] pair? Object that returns iterators that are iterated in the same order as the Map object was inserted
  • The forEach() method will perform the callbacks provided in the parameters once forEach key-value pair in the Map object, in insertion order
  • for… Of traverses 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)
}
Copy the code

In fact, Object is also a key value pair to store and read, so there are other differences between them in addition to what we said before?

  • The type of the key

The keys of an Object can only be strings or Symbols, while the keys of a Map can be any values, including functions, objects, and basic types.

  • The order of the keys

Keys in a Map are ordered, while keys added to objects are not. Therefore, when traversing it, the Map object returns key values in the order in which they were inserted.

  • Key – value pair statistics

You can directly obtain the number of key-value pairs for a Map using the size attribute, whereas the number of key-value pairs for Object can only be calculated manually.

  • Traversal of key-value pairs

A Map iterates directly, whereas an Object iterates by retrieving its key array before iterating.

  • performance

Map has some performance advantages in scenarios involving frequent addition and deletion of key-value pairs.

3.WeekMap WeakMap structure similar to Map structure, is also used to generate the set of key value pairs.

// WeakMap can add members using the set method
const wm1 = new WeakMap(a)const key = {
    foo: 1
}
wm1.set(key, 2)
wm1.get(key) / / 2

WeakMap can also accept an array,
// as arguments to the constructor
const k1 = [1.2.3]
const k2 = [4.5.6]
const wm2 = new WeakMap([
    [k1, 'foo'],
    [k2, 'bar']
])
wm2.get(k2) // "bar"
Copy the code

WeakMap differs from Map in two ways.

  • WeakMap only accepts objects as key names (except null) and does not accept values of other types as key names.
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
Copy the code
  • The object to which the key name of WeakMap points is not included in the garbage collection mechanism.

String

1. The Unicode representation

ES6 has enhanced Unicode support, allowing a character to be represented in the \uxxxx form, where XXXX represents the Unicode code point of the character.

"\u0061"
// "a"
Copy the code

However, this representation is limited to characters with code points between \u0000 and \uFFFF. Characters outside this range must be represented as two double bytes.

"\uD842\uDFB7"
/ / "𠮷"

"\u20BB7"
// " 7"
Copy the code

The code above shows that JavaScript will interpret \u20BB+7 as \u20BB+7 if you directly follow \u with a value greater than 0xFFFF (such as \u20BB7). Since \u20BB is a non-printable character, only a space is displayed, followed by a 7.

ES6 improves on this by putting the code point in braces to read the character correctly.

"\u{20BB7}"
/ / "𠮷"
Copy the code

With this notation, there are six ways that JavaScript can represent a character.

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

2. Traverser interface

ES6 adds a traversator interface for strings, as described in the Iterator section, so that strings can be used for… The of loop traverses.

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

3. Template string

  • String Literals

This is used to solve string concatenation problems, starting with ES6 you can define strings this way.

`string text` 

`string text line 1 string text line 2`

`string text ${expression} string text` 
Copy the code

Here you can insert any variable or expression you want, just wrap it in ${}.

  • Tag Literals

The previous string literals solve the problem of string concatenation, which can’t be solved by simple expressions for strings containing complex logic. So another solution was needed: Tag Literals, for example:

var retailPrice = 20
var wholesalePrice = 16
var type = 'retail'

var showTxt = ' '

if (type === 'retail') {
    showTxt += 'Your purchase price this time is:' + retailPrice
} else {
    showTxt += 'Your wholesale price is:' + wholesalePrice
}
Copy the code

You can now define a Tag function and use it as a template engine:

function Price(strings, type) {
    let s1 = strings[0]
    const retailPrice = 20
    const wholesalePrice = 16
    let txt = ' '
    if (type === 'retail') {
        txt = The unit price of purchase is:${retailPrice}` 
    } else {
        txt = The wholesale price is:${wholesalePrice}` 
    }
    return `${s1}${txt}` 
}

let showTxt = Price 'Yours this timeThe ${'retail'}` 

console.log(showTxt) // Your unit price this time is 20
Copy the code

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

4. Extend the method

  • String.prototype.fromCodePoint()

Used to return corresponding characters from Unicode code points and can recognize characters greater than 0xFFFF.

// ES5
console.log(String.fromCharCode(0x20BB7))
/ / ஷ

// ES6
console.log(String.fromCodePoint(0x20BB7))
/ / 𠮷
Copy the code
  • String.prototype.includes()

In ES5, the indexOf method can be used to determine whether a string is contained in another string. IndexOf returns the subscript position of the occurrence, or -1 if none exists.

const str = 'isxxx'

console.log(str.indexOf('is'))
Copy the code

ES6 provides an includes method to determine whether a string is included in another string, returning a Boolean value.

const str = 'isxxx'

console.log(str.includes('xx'))
Copy the code
  • String.prototype.startsWith()

Checks if the argument string is at the head of the original string, returning a Boolean value.

const str = 'isxxx'

console.log(str.startsWith('is'))
Copy the code
  • String.prototype.endsWith()

Checks if the argument string is at the end of the original string and returns a Boolean value.

const str = 'isxxx'

console.log(str.endsWith('xxx'))
Copy the code
  • String.prototype.repeat()

The repeat method returns a new string, repeating the original string n times.

const str = 'isxxx'

const newStr = str.repeat(10)

console.log(newStr)
Copy the code

RegExp

Y modifier ES6 adds a Y modifier to regular expressions, called the sticky modifier.

The y modifier is similar to the G modifier in that it is a global match, and each subsequent match starts at the position following the last successful match. The difference is that the G modifier works as long as there is a match in the remaining position, while the Y modifier ensures that the match must start at the first remaining position, which is what “bonding” means.

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
Copy the code

The code above has two regular expressions, one using the G modifier and the other using the Y modifier. The two regular expressions are executed twice each, and on the first execution, they behave the same, with the remaining strings being _aa_A. Since the G modifier has no position requirement, the second execution returns the result, while the Y modifier requires that the match must start at the head, so null is returned.

If you change the regular expression to make sure the header 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_"]
Copy the code

The Y modifier can be better illustrated with the lastIndex attribute.

const regexp = /a/g

// Specify that the match starts at position 2 (y)
regexp.lastIndex = 2

// The match is successful
const match = regexp.exec('xaya')

// The match was successful at position 3
console.log(match.index) / / 3

// The next match starts at bit 4
console.log(regexp.lastIndex) / / 4

// Bit 4 failed to start matching
regexp.exec('xaxa') // null
Copy the code

In the code above, the lastIndex attribute specifies the start of each search, from which the G modifier searches backwards until a match is found.

The y modifier also follows the lastIndex property, but requires that a match be found at the position specified by lastIndex.

const regexp = /a/y

// specify matching from position 2
regexp.lastIndex = 2

// The match failed
regexp.exec('xaya') // null

// specify matching from position 3
regexp.lastIndex = 3

// Position 3 is adhesion, match successful
const match = regexp.exec('xaxa')
console.log(match.index) / / 3
console.log(regexp.lastIndex) / / 4
Copy the code

Further, the y modifier implies the header matching flag ^.

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

Sticky mode only affects two things during regular matching:

  • Matches must start at re.lastIndex (equivalent to ^ in regular expression)
  • If it matches, it will change re.lastIndex (equivalent to g mode)

ES6 adds the U modifier to regular expressions, which stands for “Unicode mode” to properly handle Unicode characters larger than \uFFFF. That is, four bytes of UTF-16 encoding will be handled correctly.

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

/^\uD83D/.test('\uD83D\uDC2A') // true
Copy the code

In the above code, \uD83D\uDC2A is a four-byte UTF-16 encoding that stands for a character “🐪”. However, ES5 does not support the four-byte UTF-16 encoding, which is recognized as two characters, resulting in the second line of code yielding true. When you add the u modifier, ES6 recognizes it as a character, so the first line of code results in false.

Once the u modifier is added, it modifies the behavior of the following regular expressions.

  • Some characters

Dot (.) Character in a regular expression, a character is any single character except a newline character. For Unicode characters with code points greater than 0xFFFF, dot characters are not recognized and must be decorated with the U modifier.

let s = '𠮷'

/^.$/.test(s) // false

/^.$/u.test(s) // true
Copy the code
  • Unicode character representation

ES6 has added curly braces for Unicode characters, which must be recognized by the U modifier in regular expressions.

/\u{61}/.test('a') // false

/\u{61}/u.test('a') // true

/\u{20BB7}/u.test('𠮷') // true
Copy the code
  • quantifiers

With the U modifier, all quantifiers correctly recognize 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
Copy the code
  • Predefined schema

The u modifier also affects the predefined schema’s ability to correctly recognize Unicode characters with code points greater than 0xFFFF.

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

/^\S$/u.test('𠮷') // true
Copy the code

The \S of the code above is a predefined pattern that matches all characters that are not Spaces. It can correctly match Unicode characters with code points greater than 0xFFFF only if the u modifier is added.

Using this, you can write a function that returns the correct 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
Copy the code
  • The I modifier

Some Unicode characters have different encodings but similar fonts, for example, \u004B and \u212A are capitalized K.

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

/[a-z]/iu.test('\u212A') // true
Copy the code

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

Number

Binary and octal

  • How to convert decimal to binary in JS?
const a = 5 / / 101

console.log(a.toString(2))
Copy the code
  • How do I convert octal to binary?
const b = 101

console.log(parseInt(b, 2))
Copy the code

ES6 provides a new way to write binary and octal values, represented by prefixes 0b (or 0b) and 0O (or 0O), respectively.

const a = 0B0101
console.log(a)

const b = 0O777
console.log(b)
Copy the code

2. Add methods

  • Number.isFinite()

Used to check if a number is finite, i.e. 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
Copy the code
  • Number.isNaN()

Used to check if 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
Copy the code
  • Number.parseInt()

ES6 migrates the global method parseInt() onto the Number object, leaving the behavior exactly the same. The goal is to gradually reduce the global approach and make the language more modular.

// ES5
parseInt('12.34') / / 12

// ES6
Number.parseInt('12.34') / / 12
Copy the code
  • Number.parseFloat()

ES6 ports the global method parseFloat() onto the Number object, leaving the behavior exactly the same. The goal is to gradually reduce the global approach and make the language more modular.

// ES5
parseFloat('123.45 #') / / 123.45

// ES6
Number.parseFloat('123.45 #') / / 123.45
Copy the code
  • 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
Copy the code
  • Number.MAX_SAFE_INTEGER
Number.MAX_SAFE_INTEGER === Math.pow(2.53) - 1 // true

Number.MAX_SAFE_INTEGER === 9007199254740991 // true
Copy the code
  • Number.MIN_SAFE_INTEGER
Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER // true

Number.MIN_SAFE_INTEGER === -9007199254740991 // true
Copy the code
  • Number.isSafeInteger()

The range of integers that JavaScript can accurately represent is between -2^53 and 2^53 (excluding the two endpoints), beyond which this value cannot be accurately represented.

Math.pow(2.53) / / 9007199254740992

Math.pow(2.53) = = =Math.pow(2.53) + 1 // true
Copy the code

3. The Math

  • Math.trunc()

The () method is used to remove the fractional 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
Copy the code
  • Math.sign()

The method is used to determine whether a number is positive, negative, or zero. For non-numeric values, they are converted to numeric values first.

It returns five values.

  • Argument is positive, return +1
  • Argument is negative, return -1
  • Argument is 0, return 0
  • Argument -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
Copy the code
  • Math.cbrt()

The cube root () method is used to calculate the cube root of a number.

console.log(Math.cbrt(8)) / / 2

console.log(Math.cbrt('xx')) // NaN
Copy the code

Proxy

A very powerful addition to the ES6 standard is Proxy, which can customize common behavior such as lookup, assignment, enumeration, function calls, and so on. It can also be seen from the name Proxy that it contains the meaning of “Proxy”. As long as there is a demand for “Proxy”, we can consider using Proxy to achieve it.

1. Basic grammar

let p = new Proxy(target, handler)
Copy the code
parameter meaning Will choose
target A target object wrapped in a Proxy (which can be any type of object, including a native array, a function, or even another Proxy) y
handler An object whose properties are functions that define the behavior of the agent when an operation is performed y
2. Common interception operations
  • get

Intercepts 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])
Copy the code
let dict = {
    'hello': 'hello'.'world': 'the world'
}
dict = new Proxy(dict, {
    get(target, prop) {
        return prop in target ? target[prop] : prop
    }
})
console.log(dict['world'])
console.log(dict['imooc'])
Copy the code
  • set

Intercepting object property Settings, such as proxy.foo = v or proxy[‘foo’] = v, 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)
Copy the code
  • has

Intercepts the propKey in proxy operation, returning 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)
Copy the code
  • ownKeys

Interception Object. GetOwnPropertyNames (proxy), Object. GetOwnPropertySymbols (proxy), the Object. The keys (proxy), for… The in loop returns an array. This method returns the property names of all of the target Object’s own properties, whereas object.keys () returns only 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))
Copy the code
  • deleteProperty

Intercepts the delete Proxy [propKey] operation, returning a Boolean value.

let user = {
    name: 'xxx'.age: 18._password: '* * *'
}
user = new Proxy(user, {
    get(target, prop) {
        if (prop.startsWith('_')) {
            throw new Error('Inaccessible')}else {
            return target[prop]
        }
    },
    set(target, prop, val) {
        if (prop.startsWith('_')) {
            throw new Error('Inaccessible')}else {
            target[prop] = val
            return true}},deleteProperty(target, prop) { // Block delete
        if (prop.startsWith('_')) {
            throw new Error('Undeletable')}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)
}
Copy the code
  • apply

Intercepting operations called by Proxy instances as functions, such as Proxy (… The args), proxy. Call (object,… The args), proxy. Apply (…). .

let sum = (. args) = > {
    let num = 0
    args.forEach(item= > {
        num += item
    })
    return num
}

sum = new Proxy(sum, {
    apply(target, ctx, args) {
        returntarget(... args) *2}})console.log(sum(1.2))
console.log(sum.call(null.1.2.3))
console.log(sum.apply(null[1.2.3]))
Copy the code
  • construct

Intercepting operations called by Proxy instances as constructors, such as new Proxy (… The args).

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

Reflect

Reflect objects, like Proxy objects, are a new API provided by ES6 for manipulating objects.

1. Design purpose

  • Add methods that Object is internal to the language to 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)
Copy the code
  • Modify the return results of some Object methods to make them more reasonable
/ / the old way
try {
    Object.defineProperty(target, property, attributes)
    // success
} catch (e) {
    // failure
}

/ / a new way
if (Reflect.defineProperty(target, property, attributes)) {
    // success
} else {
    // failure
}
Copy the code
  • Make the Object operation function behavior
/ / the old way
'assign' in Object // true

/ / a new way
Reflect.has(Object.'assign') // true
Copy the code
  • The Reflect method corresponds to the Proxy method. As long as it is a Proxy method, 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
    }
})
Copy the code

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

2. Common methods

  • Reflect.apply()

Apply (target, thisArgument, argumentsList),target is the target function; ThisArgument is the this object bound to the target function call; ArgumentsList is the list of arguments passed in when the target function is called. The argument 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"
Copy the code
  • Reflect.construct()

The reflect.construct () method behaves a bit like the new operator constructor, equivalent to running a new target(… args)

var d = Reflect.construct(Date[1776.6.4])
d instanceof Date // true
d.getFullYear() / / 1776
Copy the code
  • Reflect.define​Property()

The static method reflect.defineProperty () is basically the same as object.defineProperty (), except that it returns a Boolean value.

const student = {}
Reflect.defineProperty(student, 'name', {
    value: 'Mike'
}) // true
student.name // "Mike"
Copy the code
  • Reflect.delete​Property()

Reflect.deleteProperty allows you to delete a property on an object. Returns a Boolean value indicating whether the property was successfully deleted. It is almost identical to a 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]

// If the attribute does not exist, return true
Reflect.deleteProperty({}, "foo") // true

// If the property is not configurable, return false
Reflect.deleteProperty(Object.freeze({
    foo: 1
}), "foo") // false
Copy the code
  • Reflect.get()

The reflect.get () method works just like getting a property from object (Target [propertyKey]), but it executes 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"
Copy the code
  • Reflect.get​OwnProperty​Descriptor()

Static methods Reflect. GetOwnPropertyDescriptor () with the Object. GetOwnPropertyDescriptor () method is similar. Returns the property descriptor for the given property if it exists in the object, otherwise 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}
Copy the code
  • Check out Reflect for more tips

Promise

1. Basic grammar

Promise was designed to solve the problem of “callback hell” by making the handling of asynchronous operations elegant. The callback hell, the code is difficult to maintain, and often the output of the first function is the input of the second function. Promise can support multiple concurrent requests, and retrieve the data in the concurrent request. This promise can solve the problem of asynchrony.

Create the Promise instance.

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

    if ( /* Asynchronous operation succeeded */ ) {
        resolve(value)
    } else {
        reject(error)
    }
})
Copy the code

The Promise constructor takes a function as an argument, resolve and reject. They are two functions that are provided by the JavaScript engine and do not need to be deployed themselves.

  • If the result is normal, call resolve, change the state of the Promise object from “unfinished” to “successful” (from pending to Resolved), call it when the asynchronous operation succeeds, and pass the result of the asynchronous operation as a parameter
  • To handle an Error, call reject(Error object), change the state of the Promise object from “unfinished” to “failed” (from pending to Rejected), call it when the asynchronous operation fails, and pass the Error from the asynchronous operation as a parameter.

After the Promise instance is generated, you can use the THEN method to specify the resolved and Rejected state callback functions, respectively.

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

A Promise is internally stateful (pending, depressing, and Rejected). The Promise object determines which method to implement according to the state. The Promise state is default pending when it is instantiated. 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('Value passed to THEN')
})
promise.then(function(value) {
    console.log(value)
}, function(error) {
    console.error(error)
})
Copy the code
  • When the handler returns a normal value, this value is passed to the onFulfilled method of the Promise object.
  • This value is passed to the onRejected method of the Promise object when an exception is raised in the handler defined.

3, Promise. Prototype. The catch ()

Catching exceptions is a basic requirement for program quality assurance. You can use the catch method of the Promise object to catch 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
})
Copy the code

4, Promise. Resolve ()

Normally we use new Promise() to create a Promise object, but we can use other methods as well.

Here, we’ll learn how to use the promise. resolve and promise. reject methods.

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

For example promise.resolve (42) can be thought of as syntactic sugar for the following code.

new Promise(function(resolve) {
    resolve(42)})Copy the code

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

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

5, Promise. Reject ()

Promise.reject(error) is a static method similar to promise.resolve (value) that is a shortcut to the new Promise() method.

For example, promise.reject (new Error(” Error “)) is the syntactic sugar form of the code below.

new Promise(function(resolve, reject) {
    reject(new Error('Wrong'))})Copy the code

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

Promise.reject(new Error('BOOM! '))
Copy the code

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]
})
Copy the code

Promise.all generates and returns a new Promise object, so it can use all the methods of a Promise instance. The method returns when all the promise objects in the promise array become resolve, and newly created promises use those promise values.

If any of the promises in the arguments is reject, the entire promise. all call terminates immediately and returns a new Reject Promise object.

Because each element in the parameters array is wrapped (wrap) 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
})
Copy the code

Promise.race generates and returns a new Promise object.

If any of the promise objects in the promise array are changed to resolve or reject, this function returns and uses the promise value 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 is hard to understand, take a look at the following example.

  1. Regular cycle
for (let i = 0; i < 5; i += 1) {
    console.log(i)
}
// this will return immediately 0 -> 1 -> 2 -> 3 -> 4
Copy the code
  1. Use of the 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
Copy the code

In contrast to code, a regular loop can only iterate through all values once, and the Generator can call the next method to get the values iterated in sequence, making the execution of the loop “controllable”.

1. Basic grammar

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

let g = gen()
// "Generator { }"
Copy the code

This is how Generator is defined, with a few points worth noting:

  • One more star than a normal function
  • Internal use of yield to control the “pause” of program execution
  • The return value of the function is called next to “resume” program execution

Generator functions cannot be defined using arrow functions, otherwise SyntaxError will be raised

let generator = * () = > {} // SyntaxError
let generator = () * => {} // SyntaxError
let generator = ( * ) = > {} // SyntaxError
Copy the code

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

  • The yield expression returns undefined, but the next method of the iterator object can change this default value.
  • The next method on a Generator object pauses at yield and returns an object with two properties: 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.log( ` 3:${val}` ) // 3:undefined
  }

  var g = gen()

  console.log(g.next()) // {value: 1, done: false}
  console.log(g.next()) // {value: 2, done: false}
  console.log(g.next()) // {value: 3, done: false}
  console.log(g.next()) // {value: undefined, done: true}
Copy the code

3, methods,

Generator objects have several methods, next, return, and throw.

  • next([value])

The Generator object gets the result of each iteration through the next method, which returns an object containing two properties: Value and done. Value indicates the running result of the current program, and done indicates whether the traversal is complete.

Next accepts arguments that allow you to pass data from the outside of the Generator to the inside as yield returns.

function* gen() {
      var val = 100
      while (true) {
          console.log( `before ${val}` )
          val = yield val
          console.log( `return ${val}`)}}var g = gen()
  console.log(g.next(20).value)
  // before 100
  / / 100
  console.log(g.next(30).value)
  // return 30
  // before 30
  / / 30
  console.log(g.next(40).value)
  // return 40
  // before 40
  / / 40
Copy the code
  • return()

The return method terminates the Generator traversal, similar to the break of the for loop.

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

var g = gen()

console.log(g.next()) // {value: 1, done: false}
console.log(g.return()) // {value: undefined, done: true}
console.log(g.next()) // {value: undefined, done: true}
Copy the code
  • throw()

You can use the throw method to control the “finalization” performed internally from outside the Generator.

function* gen() {
    while (true) {
        try {
            yield 42
        } catch (e) {
            console.log(e.message)
        }
    }
}

let g = gen()
console.log(g.next()) // { value: 42, done: false }
console.log(g.next()) // { value: 42, done: false }
console.log(g.next()) // { value: 42, done: false }
// Interrupt the operation
g.throw(new Error('break'))

console.log(g.next()) // {value: undefined, done: true}
Copy the code

Iterator

It is a common operation to process each item in a collection. JavaScript provides many methods for iterating over collections, from simple for loops to map() and filter(). Iterators and generators bring the concept of iteration directly into the core language and provide a mechanism for customizing for… The act of cycling.

If you don’t quite understand the description of MDN, take a look at the following small example:

let authors = {
    allAuthors: {
        fiction: [
            'Agatha Christie'.'J. K. Rowling'.'Dr. Seuss'].scienceFiction: [
            'Neal Stephenson'.'Arthur Clarke'.'Isaac Asimov'.'Robert Heinlein'].fantasy: [
            'J. R. R. Tolkien'.'J. K. Rowling'.'Terry Pratchett']}}Copy the code

This data structure is a summary of all authors, each classified by the nature of their work. What if we wanted to get a list of all authors?

for (let author of authors) {
    console.log(author)
}
Copy the code

Uncaught TypeError: authors is not iterable

1. Basic grammar

Iterator is an ES6 interface used to implement custom traversal.

authors[Symbol.iterator] = function() {
    let allAuthors = this.allAuthors
    let keys = Reflect.ownKeys(allAuthors)
    let values = []
    return {
        next() {
            if(! values.length) {if (keys.length) {
                    values = allAuthors[keys[0]]
                    keys.shift()
                }
            }
            return {
                done: !values.length,
                value: values.shift()
            }
        }
    }
}
Copy the code

This code deploys the Iterator interface on the data structure, so we can use for… Of iterates through the code:

for (let value of authors) {
    console.log( `${value}`)}Copy the code

Iterable protocol and iterator protocol.

    1. Iterator protocol

There are two concepts: iterable protocol and iterator protocol. In layman’s terms, the iterator protocol requires the following:

  • First of all, it’s an object
  • Second, this object contains a function with no arguments, next
  • Finally, next returns an object containing the done and Value properties. Done indicates whether the traversal is complete, and value returns the current traversal value.
    1. Iterable protocol

The iterable protocol allows JavaScript objects to define or customize their iterative behavior, such as in a for.. What values in the of structure can be looped. Some built-in types are built-in iterable types and have the default iterative behavior, such as Array or Map, while others are not (such as Object).

To become iterable, an object must implement the @@iterator method, which means that the object (or an object in its prototype chain) must have a property named symbol. iterator.

If an object is traversable, it follows the iterable protocol, which requires that the object deploys a key-value pair with symbol. iterator as the key. Value is a no-argument function that returns an object that complies with the iterator protocol.

3, the Generator

Once you became familiar with the Generator, you found it to be a natural fit for iterable protocols. We can use Generator to implement the above code:

authors[Symbol.iterator] = function* () {
    let allAuthors = this.allAuthors
    let keys = Reflect.ownKeys(allAuthors)
    let values = []
    while (1) {
        if(! values.length) {if (keys.length) {
                values = allAuthors[keys[0]]
                keys.shift()
                yield values.shift()
            } else {
                return false}}else {
            yield values.shift()
        }
    }
}
Copy the code

The same scenario, the same data structure, is written differently, and using Generator eliminates the need for the displayed write iteration protocol (the next method and the return object containing the done and value attributes).

Module

1. The development of modularization

No modularity –>CommonJS specification –>AMD specification –>CMD specification –>ES6 modularity

1, CommonJS specification Node modular specification

The birth of Commonjs has given important inspiration to the modular development of JS. Commonjs is very popular, but its limitations are obvious: Commonjs based on Node native API can realize module synchronous loading on the server side, but it is only limited to the server side. If the client side synchronously loads dependencies, the time consumption is very large, so it needs a solution based on Commonjs on the client side but improving the loading module, so AMD specification was born.

2. The AMD specification, asynchronous module definition, allows you to specify callback functions. AMD is the standardized output of RequireJS module definition in the promotion process. It loads modules asynchronously without affecting the execution of subsequent statements. All statements that depend on this module are defined in a callback function that will not run until all dependencies have been loaded (pre-dependencies).

3. CMD specification, also inspired by Commonjs, a CMD (Common Module Definition) specification was born in China (Ali). This specification draws on Commonjs specification and AMD specification, and makes improvements on both basis.

CMD is the normalized output of SeaJS module definitions during the roll-out process.

AMD advocates a reliance on front-loading, front-loading, CMD advocates a reliance on nearby, delayed execution.

4. In 2015, the ES6 specification finally included modularity into the JavaScript standard. Since then, JS modularity has been officially supported, which is also the future JS standard. In ES6, we can use the import keyword to import modules, and export modules through the exprot keyword, which is more powerful than the previous several schemes, and we also recommend it. However, because ES6 cannot be implemented in the browser, so, Babel is the only way to compile an unsupported import into the currently widely supported require.

2, the export

The function of the module consists of two commands: export and import. The export command is used to specify the external interface of a module, and the import command is used to input functions provided by other modules.

A module is an independent file. All variables inside the file are not available externally. If you want outsiders to be able to read a variable inside a module, you must use the export keyword to output that variable.

  • Export a variable or constant
export const name = 'hello'
export let addr = 'BeiJing City'
export var list = [1.2.3]
Copy the code

or

const name = 'hello'
let addr = 'BeiJing City'
var list = [1.2.3]
export {
  name,
  addr,
  list
}
Copy the code
  • The export function
export function say(content) {
  console.log(content)
}
export function run() {
  console.log('run')}Copy the code

or

const say = (content) = > {
  console.log(content)
}
let run = () = > {
  console.log('run')}export {
  say,
  run
}
Copy the code
  • Export Object
export ({
  code: 0.message: 'success'
})
Copy the code

or

let data = {
  code: 0.message: 'success'
}
export {
  data
}
Copy the code
  • Derived Class
class Test {
  constructor() {
      this.id = 2}}export {
  Test
}
Copy the code

or

export class Test {
  constructor() {
      this.id = 2}}Copy the code

3, the as

If you want to rename the input variable, the import command uses the as keyword to rename the input variable.

  const name = 'hello'
  let addr = 'BeiJing City'
  var list = [1.2.3]
  export {
      name as cname,
      addr as caddr,
      list
  }
Copy the code

4, the export default

When using the import command, the user needs to know the name of the variable or function to be loaded; otherwise, the command cannot be loaded. However, users will want to get started quickly and may not want to read the documentation to learn what properties and methods a module has.

To make it easier for users to load the module without reading the documentation, use the export default command to specify the default output for the module.

const name = 'hello'
let addr = 'BeiJing City'
var list = [1.2.3]
export {
  name as cname,
  addr as caddr
}
export default list
Copy the code

5, the import

After the module’s external interface is defined using the export command, other JS files can load the module using the import command.

  • Direct import

Suppose the export module A looks like this:

const name = 'hello'
let addr = 'BeiJing City'
var list = [1.2.3]
export {
  name as cname,
  addr as caddr
}
export default list
Copy the code

Import:

import list, {
  cname,
  caddr
} from A
Copy the code
  • Modifying the Import Name
import list, {
  cname as name,
  caddr
} from A
Copy the code
  • Bulk import
  import list, * as mod from A
  console.log(list)
  console.log(mod.cname)
  console.log(mod.caddr)
Copy the code

ECMAScript2016 (ES7)

Array.prototype.includes()

The array.prototype.includes () method introduced in ES7 is used to determine if an Array contains a specified value, returning true if it does and false otherwise.

  • Basic usage
const arr = ['es6'.'es7'.'es8']
console.log(arr.includes('es6')) // true
console.log(arr.includes('es9')) // false
Copy the code
  • Take two arguments

The value to be searched and the starting index of the search. The second parameter is optional. The search for searchElement starts at that index. If it’s negative,

const arr = ['es6'.'es7'.'es8']
console.log(arr.includes('es7'.1)) // true
console.log(arr.includes('es7'.2)) // false
console.log(arr.includes('es7', -1)) // false
console.log(arr.includes('es7', -2)) // true
Copy the code
  • Compared with indexOf ()
['a'.'b'.'c'].includes('a') //true
['a'.'b'.'c'].indexOf('a') > -1 //true

console.log(arr.indexOf('es7')) / / 1
console.log(arr.indexOf('es7') > -1) // true
Copy the code

If you just want to know if a value exists in the array without caring about its index location, use includes(). If you want to get the position of a value in an array, you can only use indexOf.

The power operator **

exponentiation

console.log(2支那10) / / 1024
Copy the code

ECMAScript2017 (ES8)

async / await

Async and await are more elegant asynchronous programming solutions that are extensions of Promise.

  • The basic grammar

The async function will automatically return a Promise object after execution:

async function foo() {
    return 'xxx' // Promise.resolve('xxx')

    // let res = Promise.resolve('xxx')
    // console.log(res)
}
console.log(foo()) // Promise
foo()
Copy the code

‘await’ needs to be followed by an asynchronous operation, otherwise it makes no sense, and a Promise object after ‘await’ need not write ‘then’ because one of the purposes of ‘await’ is to get the parameters passed by the success state of the Promise object behind it.

function timeout() {
    return new Promise(resolve= > {
        setTimeout(() = > {
            console.log(1)
            resolve() // resolve('success')
        }, 1000)})}// async and await are 2 and 1 respectively
async function foo() {
    await timeout() // let res = await timeout(
    console.log(2)
}
foo()
Copy the code
  • Handling of failures
function timeout() {
    return new Promise((resolve, reject) = > {
        setTimeout(() = > {
            // resolve('success')
            reject('error')},1000)})}async function foo() {
    return await timeout()
}
foo().then(res= > {
    console.log(res)
}).catch(err= > {
    console.log(err)
})
Copy the code

The Object extension

  1. Object.values()

Object.values() returns an array of enumerable property values found on the Object. The order of properties is the same as that given by manually looping through the object’s property values (for… In, but for… In also iterates over the property values on the prototype.

const obj = {
    name: 'baidu'.web: 'www.baidu.com'.course: 'es'
}

console.log(Object.values(obj))
// ["baidu", "www.baidu.com", "es"]
Copy the code
  1. Object.entries()

The object.entries () method returns an array of key-value pairs for the given Object’s own enumerable properties, arranged in the same order as for… The in loop returns the same order as it iterates through the object. (The difference is that for-In loops also enumerate properties in the stereotype chain.)

let grade = {
    'lilei': 98.'hanmei': 87
}

for (let [key, value] of grade) {
    console.log(key, value) // Uncaught TypeError: grade is not iterable
}
Copy the code
  1. Object.getOwnPropertyDescriptors()
console.log(Object.getOwnPropertyDescriptor(data, 'Lima'))
// {value: "58/40", writable: true, enumerable: false, configurable: true}
Copy the code

String extensions

ES8 in two instances have been added to the String String. The function prototype. PadStart and String prototype. PadEnd, allows you to an empty String or other String is added to the beginning or end of the original String.

  • String.prototype.padStart()

Returns a new string by padding the specified string to the string header.

const str = 'xxx'
console.log(str.padStart(8.'x'))
console.log(str.padEnd(8.'y'))
console.log(str.padStart(8))
Copy the code

Scenario 1: Date formatting

const now = new Date(a)const year = now.getFullYear()
const month = (now.getMonth() + 1).toString().padStart(2.'0')
const day = (now.getDate()).toString().padStart(2.'0')
console.log(year, month, day)
console.log( `${year}-${month}-${day}` )
Copy the code

Scenario 2: Number substitution

// Numeric substitution, such as mobile phone number, ID number
const tel = '13012345678'
const newTel = tel.slice(-4).padStart(tel.length, The '*')
console.log(newTel) / / * * * * * * * 5678
Copy the code
  • String.prototype.padEnd()

Method populates the current string with a string (repeated if necessary) and returns the string that has been populated to the specified length. Populate from the end of the current string (right).

const str1 = 'I am learning es in imooc'
console.log(str1.padEnd(30.'. '))
// I am learning es in imooc.....

const str2 = '200'
console.log(str2.padEnd(5))
/ / "200"
Copy the code

Scenario: Uniform timestamp length

/ / pseudo code
console.log(new Date().getTime()) // The timestamp is 13 bits
timestamp = +String(timestamp).padEnd(13.'0')
Copy the code

Trailing comma Trailing commas

ES8 allows Trailing comma as the last argument to a function.

function clownsEverywhere(param1, param2,) {
    / *... * /
}

clownsEverywhere(
    'foo'.'bar'.)Copy the code

ECMAScript2018 (ES9)

for await of

Asynchronous iterators (for-await-of) : Loops waiting for each Promise object to become resolved before moving to the next step.

function Gen(time) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve(time)
        }, time)
    })
}

async function test() {
    let arr = [Gen(2000), Gen(100), Gen(3000)]
    for await (let item of arr) {
        console.log(Date.now(), item)
    }
}

test()
/ / 1560092345730 2000
/ / 1560092345730 100
/ / 1560092346336 3000
Copy the code

RegExp Updates

  • DotAll mode

In a regular expression, the point (.) Is a special character that represents any single character, with two exceptions. One is a four-byte UTF-16 character, which can be solved with the U modifier; The other is the line terminator character.

  • U+000A Newline (\n)
  • U+000D Carriage return (\r)
  • U+2028 Line separator
  • U+2029 Separator

How do you determine if the current re is using dotAll mode

const re = /foo.bar/s // Or, `const re = new RegExp('foo.bar', 's')` .
console.log(re.test('foo\nbar')) // true
console.log(re.dotAll) // true
console.log(re.flags) // 's'
Copy the code

Remember one thing to understand the dotAll pattern: It makes. Live up to its name.

  • Named Group matching

When we write a regular expression, we can wrap part of it in (), which is called “group capture”.

console.log('2020-05-01'.match(/(\d{4})-(\d{2})-(\d{2})/))
// ["2020-05-01", "2020", "05", "01", index: 0, input: "2020-05-01", groups: undefined]
Copy the code

This regex match is simple, as the syntax of match does not use the G identifier, so the first value returned is a full match of the regular expression, followed by the second through fourth values that are grouped matches (2020, 05, 01).

The match return value also has several attributes: index, input, and groups.

  1. Index [starting position of matched result]
  2. Input [search string]
  3. Groups [an array or undefined (if no named capture group is defined)]

The concept of naming capture groups is mentioned here, which is undefined if groups are not defined. Obviously, the return value of undefined means that the named capture group is not defined. So what are named capture groups?

console.log('2020-05-01'.match(/ (? 
      
       \d{4})-(? 
       
        \d{2})-(? 
        
         \d{2})/
        
       
      ))
/ / [" 2020-05-01 ", "2020", "5", "01", the index: 0, input: "2020-05-01", groups: {...}]
Copy the code

This code returns groups as Object:

groups: {
    year: "2020".month: "5".day: "01"
}
Copy the code

The key of this Object is defined in the regular expression, that is, the capture group is named. To capture these captures, do the following:

let t = '2020-05-01'.match(/ (? 
      
       \d{4})-(? 
       
        \d{2})-(? 
        
         \d{2})/
        
       
      )
/ / [" 2020-05-01 ", "2020", "5", "01", the index: 0, input: "2020-05-01", groups: {...}]
console.log(t.groups.year) / / 2020
console.log(t.groups.month) / / 05
console.log(t.groups.day) / / 01
Copy the code
  • After assertion

Prior to ES9, JavaScript re only supported prior assertions, not subsequent assertions. A quick review of prior assertions:

let test = 'hello world'
console.log(test.match(/hello(? =\sworld)/))
// ["hello", index: 0, input: "hello world", groups: undefined]
Copy the code

This code matches hello followed by world, but not the other way around:

let test = 'world hello'
console.log(test.match(/hello(? =\sworld)/))
// null
Copy the code

For example, if we want to say hello before world, this code won’t do it. The following assertion is supported in ES9:

let test = 'world hello'
console.log(test.match(/ (? <=world\s)hello/))
// ["hello", index: 6, input: "world hello", groups: undefined]
Copy the code

(? <…). Is the symbol for the following assertion, (? …). Is the predicate symbol followed by =(equal to),! (unequal), \1(capture match).

Object Rest & Spread

New Object Rest & Spread method in ES9, let’s take a look at the example:

const input = {
  a: 1.b: 2
}

constoutput = { ... input,c: 3
}

console.log(output) // {a: 1, b: 2, c: 3}
Copy the code

Let’s look at another example of Object REST:

const input = {
  a: 1.b: 2.c: 3
}

let{ a, ... rest } = inputconsole.log(a, rest) // 1 {b: 2, c: 3}
Copy the code

When the key-value of the object is uncertain, assign the required key to the variable and use a variable to converge the other optional key data, which was not possible before.

Promise.prototype.finally()

Specifies a callback function that will be executed regardless of the final state.

Promise. Prototype. Finally () method returns a Promise, the Promise at the end of the execution, no matter the result is fulfilled or is rejected, the execution then (), and the catch (), will perform the finally specify the callback function. This provides a way to specify the code that needs to be executed after the promise is fulfilled, no matter the result is pity or Rejected. This avoids the situation where the same statement needs to be written once in then() and catch().

new Promise((resolve, reject) = > {
    setTimeout(() = > {
        resolve('success')
        // reject('fail')
    }, 1000)
}).then(res= > {
    console.log(res)
}).catch(err= > {
    console.log(err)
}).finally(() = > {
    console.log('finally')})Copy the code

Scenario 1: Loading is disabled

Each time a request is sent, a loading prompt is displayed. After the request is sent, you need to disable the Loading prompt; otherwise, the loading prompt cannot be clicked. This loading must be disabled whether the request succeeds or fails. In this case, finally is a good place to stop loading.

Scenario 2: The database is disconnected

let connection
db.open()
.then(conn= > {
    connection = conn
    return connection.select({
        name: 'Jane'
    })
})
.then(result= > {
    // Process result
    // Use `connection` to make more queries}) · · ·. The catch (error= > {
    // handle errors
})
.finally(() = > {
    connection.close()
})
Copy the code

String extension

Relax the restrictions on string escape in tag templates, return undefined in case of illegal string escape, and obtain the original string from raw.

Starting with ES9, template strings allow nesting support for common escape sequences, removing syntactic restrictions on ECMAScript escaping sequences in tagged template strings.

// Tagged template string

const foo = (a, b, c, d) = > {
    console.log(a)
    console.log(b)
    console.log(c)
    console.log(d)
}
// foo(1, 2, 3, 4)
const name = 'xxx'
const age = 18
foo This is a `${name}His age is${age}At the age of ` 
Copy the code

The ES9 standard removes syntactic restrictions on escape sequences in ECMAScript tagged template strings.

function tag(strs) {
    console.log(strs)
    // strs[0] === undefined
    // strs.raw[0] === "\\unicode and \\u{55}"
}

// used in tag functions
tag `\u{61} and \u{62}`  //
tag `\u{61} and \unicode`  // the result is undefined

// The previous version reported an error: Invalid Unicode escape sequence
// Invalid Unicode escape sequence

/ / error:
let bad = `bad escape sequence: \unicode` 
Copy the code

ECMAScript2019 (ES10)

Object.fromEntries()

Object.fromentries () converts the list of key-value pairs into an Object, as opposed to Object.entries().

Object.fromEntries([
    ['foo'.1],
    ['bar'.2]])// {foo: 1, bar: 2}
Copy the code

String extensions

  • String.prototype.trimStart()

The trimStart() method removes whitespace from the beginning of the string, and trimLeft() is the alias for this method.

let str = ' foo '
console.log(str.length) / / 8
str = str.trimStart()
console.log(str.length) / / 5
Copy the code
  • String.prototype.trimEnd()

The trimEnd() method removes whitespace from the right end of a string. TrimRight is the alias for trimEnd.

let str = ' foo '
console.log(str.length) / / 8
str = str.trimEnd()
console.log(str.length) / / 6
Copy the code

Array extension

  • Array.prototype.flat()

The Flat () method recurses through the array of numbers at a specified depth and returns all the elements in a new array combined with the elements in the traversed subarray.

const numbers = [1.2[3.4[5.6]]]
console.log(numbers.flat())
// [1, 2, 3, 4, [5, 6]]
Copy the code

At this point, the parameter of flat is not set, and the default value is 1, that is, the next level is flattened. When [3, 4, [5, 6] is encountered, the array will be flattened and processed, and no longer traverses the internal elements to see if there is an array

const numbers = [1.2[3.4[5.6]]]
console.log(numbers.flat(2))
// [1, 2, 3, 4, 5, 6]
Copy the code

When flat is greater than or equal to 2, the return value is [1, 2, 3, 4, 5, 6].

  • Array.prototype.flatMap()

The flatMap() method first maps each element using a mapping function and then compresses the result into a new array. As can be seen from the name of the method, it contains two functions: map and flat (depth 1).

const numbers = [1.2.3]
numbers.map(x= > [x * 2]) / / [[2], [4], [6]]
numbers.flatMap(x= > [x * 2]) / / (2, 4, 6]
Copy the code

This example is a simple comparison between a Map and a flatMap. Of course, you can also look at the following example:

let arr = ['It's a nice day'.' '.'Good morning']
arr.map(s= > s.split(' '))
/ / [[" today ", "day", "day", "gas", "no" and "wrong"], ["], [" early ", "on", "good"]]
arr.flatMap(s= > s.split(' '))
/ / / "today", "day", "day", "gas", "no" and "wrong", ""," early ", "on", "good"]
Copy the code

Revision of the Function. The prototype. The toString ()

Function is an Object, and each Object has a. The toString () method, because it exists in the originally Object. The prototype, the toString (). All objects, including functions, are inherited from it through prototype-based class inheritance. This means we already had the funcion.toString() method before.

Function. The prototype. The toString () method returns a string source said that the current Function.

This means that comments, Spaces, and syntax details are also returned.

function foo() {
    // New es10 features
    console.log('xxxx')}console.log(foo.toString())

// Directly in the method name toString()
console.log(Number.parseInt.toString())
Copy the code

Optional Catch Binding

Before ES10 we used to catch exceptions like this:

try {
    // tryCode
} catch (err) {
    // catchCode
}
Copy the code

Err is mandatory here and can be omitted in ES10:

try {
    console.log('Foobar')}catch {
    console.error('Bar')}Copy the code

JSON extension

  • JSON superset

What is a JSON superset? In short, make ECMAScript compatible with all JSON supported text. ECMAScript states in the standard Json.parse section that JSON is a subset of this, but because JSON content can normally contain U+2028 line delimiters and U+2029 paragraph delimiters, ECMAScript does not.

  • Json.stringify () improves capabilities

Json.stringify in ES10 fixes a problem with some out-of-scope Unicode presentation errors. Because JSON is encoded to UTF-8, characters in 0xD800-0xDFFF cannot be encoded to UTF-8, resulting in display errors. In ES10 it will escape characters instead of encoding them, and it will display normally.

// \uD83D\uDE0E emoji multi-byte one character
console.log(JSON.stringify('\uD83D\uDE0E')) / / smiling face

// If we only go to part of it \uD83D this is actually an invalid string
// In previous versions, these characters were replaced with special characters, while unpaired proxy code points are now represented as JSON escape sequences
console.log(JSON.stringify('\uD83D')) // "\ud83d"
Copy the code

Symbol extension

  • Symbol.prototype.description

Read-only property that returns a string of optional descriptions of the Symbol object.

The Symbol’s Description is stored in the internal Description of the Symbol, and is not exposed directly. We can only read this property when we call Symbol’s toString() :

const name = Symbol('es')
console.log(name.toString()) // Symbol(es)
console.log(name) // Symbol(es)
console.log(name === 'Symbol(es)') // false
console.log(name.toString() === 'Symbol(es)') // true
Copy the code

We can now obtain the description of the Symbol using the description method:

const name = Symbol('es')
console.log(name.description) // es
console.log(name.description === 'es') // true
Copy the code

Write in the back

Word limit ES11 to ES12 See Ecmascript2020-2021

Refer to the article

  • New JavaScript ES12 features get a head start
  • ES6, ES7, ES8, ES9, ES10, ES11, ES12 new features
  • ECMAScript2015 to 2020 Syntax is fully parsed