Introduction to ECMASCript

1. The Javascript language itself refers to ECMASCript, but Javascript is extended to run on different platforms. 2, the use of Javascript in the Web includes: ECMASCript + Web APIs (BOM, DOM). Javascript in Node.js includes ECMASCript + Node APIs (fs, NET, etc.). 4. Since 2016, ES has maintained an annual version iteration, and what we call ES6 in the industry can refer to all ECMASCript standards in general. 5. ES6 has made great improvement on the original foundation, mainly reflected in four aspects:

  • Enhancements to existing syntax, such as:Object.values(),Object.assign().
  • Solve some problems or defects in the original syntax, such as:let,const,Block scope.
  • New object, new method, new function, such as:Proxy,Reflect,classKeywords,extendsClass inheritance…
  • New data types and data structures such as:Symbol,Set,Map.

Array deconstruction, object deconstruction

1. In the past, the way to obtain array elements is by array subscript. ES6 can obtain array elements by assigning values according to the same position, and can also add default values. In addition, the collection can be obtained through the residual operator.

const arr = [100.200.300]
const [foo, bar, baz, car = 400] = arr
const [bas, ...rest] = arr
log(foo, bar, baz, car)  // 100 200 300 400
log(bas, rest)  // 100 [200, 300]
Copy the code

2. In the past, the way to obtain object attributes is through. ES6 can get the value of an attribute by having the same variable name as the attribute name, or it can rename the attribute name to add a default value to the attribute value.

const obj = { name: 'Tom'.age: 20 }
const name = 'Jack'
const { name: objName = 'default' } = obj
log(objName)  // Tom
Copy the code

Template string and extension method

1, template string common usage support variables, back quotes escape, line feed, interpolation operations

const name = 'peek'
log(`hello es2015
my name is ${name + 1} \`\string\``)
Copy the code

2. Tagged template strings can manipulate strings

const name = 'peek'
const gender = true
function myTagFunc (string, name, gender) {
    return string[0] + name + string[1] + gender + string[2]}const result = myTagFunc`hey, ${name} is a ${gender}`
console.log(result)  // hey, peek is a true
Copy the code

3, ES6 provides string extension methods

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

Four,… The operator

1. Residual operators are used to pass function parameters, preferably at the end of the parameter

const hello = (sum, ... rest) = > {
    log(sum)  / / 100
    log(rest)  // [1, 2, 3]
}
hello(100.1.2.3)
Copy the code

2. Use extension operators in arrays

const arr = ['1'.'2'.'3']
console.log(... arr)/ / 1 2 3
Copy the code

Object literals are enhanced

const x = '11'
const family = {
    x,
    y () { //
        console.log(this) // this points to family
    },
    z: () = > { //
        log(this.y) // This points to window
        log(family.y) // Call the property of the family object
        return null
    },
    // Calculate the attribute name as the attribute name
    [Math.random()]: '33'
}

console.log(family)
Copy the code

Object new method

log(Object.assign({ a: 1.b: 2 }, { a: 3.c: 4 })) // Object merge
log(Object.assign({}, { a: 3.c: 4 })) / / shallow copy
log(-0= = = +0) // true
log(null= = =null) // true
log(Object.is(-0, +0)) // false Determines whether objects are equal
log(Object.is(null.null)) // true
Copy the code

Vii. Proxy Object (commonly known as: Gatekeeper)

1. Proxy object hijacks the whole object in a non-invasive way and supervises the whole object

const person = {
    name: 'Tom'.age: 24
}
const personProxy = new Proxy(person, {
    get (target, prop) {
        // 1. Add the default value and return the value of the attribute
        return target[prop] ? target[prop] : 'default'
    },
    set (target, prop, value) { // trivia: vscode suggests that the code is not what we need, just press Esc
        // add verification and exception handling to the assignment of object attributes
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new Error('this value must be a integer')}}// 3. Assign a value to the object attribute
        target[prop] = value
    }
})

personProxy.age = '20'
log(personProxy.name)
log(personProxy.xxx)
Copy the code

Object. DefineProperty only supports the hijacking of the read and write of the Object, and it is an intrusive writing method, which needs to modify the Object. Proxy supervises the entire object and hijacks the entire object in a non-intrusive way.

const person = {
    name: 'Tom'.age: 24
}
const personProxy = new Proxy(person, {
    set (target, prop, value) {
        target[prop] = value
    },
    deleteProperty (target, prop) {
        console.log('delete', prop)
        delete target[prop]
    }
})

delete personProxy.age
personProxy.gender = 'man'
log(person) // { name: 'Tom', gender: 'man' }
Copy the code

Proxy is more friendly to the array operation monitoring, the past is to rewrite the array method to realize the array listening (vue2+)

const list = []
const listProxy = new Proxy(list, {
    set (target, prop, value) {
        target[prop] = value
        return true // The array element was added successfully
    }
})

listProxy.push('11')
log(list) / / / '11'
Copy the code

3, in addition to the above commonly used property operations, there are other operations, as follows:

Reflect static class

Why it was born: The Reflect static class provides uniform methods for manipulating objects. In the past, we used very miscellaneous methods to manipulate objects, such as delete, in, object.keys (), which will be discarded in the future.

const person = {
    name: 'Tom'.age: 24
}

log('name' in person)
// Determine whether an object has an attribute, and the function of the in operator is exactly the same.
log(Reflect.has(person, 'name'))
log(delete person.name)
Delete target[name]; // Delete target[name];
log(Reflect.deleteProperty(person, 'name'))
log(Object.keys(person))
// Returns an array containing all of its own attributes (excluding inherited attributes). Keys () similar to Object.keys() but not affected by Enumerable.
log(Reflect.ownKeys(person))
Copy the code

You can modify the previous Proxy method for obtaining object attributes

const personProxy = new Proxy(person, {
    get (target, prop, value) {
        log('watch ... ')
        return Reflect.get(target, prop)
    }
})

console.log(personProxy.age)
Copy the code

In addition to the usual property operations above, there are other operations as follows:

I Promise you

Briefly, refer to handwritten promises

X, class keywords

Purpose: To make Javascript class definitions simple and easy to understand. 1. We used to define a class as a constructor, as follows:

function Person (value) {
    this.name = value
}
Person.create = function (value) { // ES5 defines static methods for classes
    return new Person(value)
}
Person.prototype.say = function () {
    log(`hi, my name is The ${this.name}`)}// const person = new Person()
const person = Person.create('Tom')
person.say()
Copy the code

2, Now we use the class keyword to define the class, concise and easy to understand

class Person {
    constructor(value) {
        this.name = value
    }
    say () {
        log(`hi, my name is The ${this.name}`)}static create (value) { // ES6 defines static methods for classes
        return new Person(value)
    }
}

// const person = new Person('Tom')
const person = Person.create('Tom')
person.say()
Copy the code

Extends class inheritance

The purpose of birth: To make class inheritance easier to understand.

class Person {
    constructor(value) {
        this.name = value
    }
    say () {
        log(`hi, my name is The ${this.name}`)}}class Student extends Person {
    constructor(name, number) {
        super(name) // The super object always refers to the superclass. Calling it calls the superclass constructor
        this.number = number
    }
    hello () {
        super.say()
        log(`my school number is The ${this.number}`)}}// extends implements class inheritance, which is simpler and easier to understand than prototype inheritance in ES5
const student = new Student('jack'.101)
console.log(student.hello())
Copy the code

12. Set data structure

What it means to be born: A Set object allows you to store a unique value of any type, either a primitive value or an object reference.

const list = new Set(a)// There is no duplicate element in the data set
list.add(1).add(2).add(2).add(4) // The add method returns the collection itself, so it can be called chained

for (i of list) {
    log(i)
}

log(list.delete(4))
log(list.size)
log(list.has(4))
// A common scenario is array de-duplication
const arr = [1.1.4.4.5.6]
log(Array.from(new Set(arr)))
log([...new Set(arr)])
Copy the code

Map data structure

Meaning: A strict collection of key-value pairs that can take any data type as a key. 1. Objects that have traditionally used multiple data types as key values

const obj1 = {
    [123] :'123'[true] :'true'[{a: 1}] :'a'[{b: 1}] :'b',
}

log(Object.keys(obj1)) // [ '123', 'true', '[object Object]' ]
log(obj1['[object Object]']) // b
Copy the code

Problem: the key values by default Object. The prototype. ToString. Call 2, ES6 key (key) to a string value to the collection of definitions

const obj2 = new Map(a)const tom = { name: 'tom' }

obj2.set(tom, 'c')
log(obj2)
obj2.forEach((value, key) = > log(value, key))
log(obj2.get(tom))
log(obj2.has(tom))
log(obj2.delete(tom))
log(obj2.clear())
Copy the code

Symbol Basic data type

1, in the past, when different files repeatedly define the same attribute of the global object overwrite the problem, the following simulation of different files.

const cache = {}
/* -----------------a.js--------------------- */
cache['foo'] = '111'

/* ----------------b.js--------------------- */
cache['foo'] = '222'
log(cache) // { foo: '222' }
Copy the code

2. The Symbol type can define constants and add descriptions of Symbol data

const s = Symbol('foo')
log(typeof s) // Symbol
log(Symbol('foo')) // Symbol(foo) Adds a description of the Symbol data
log(Symbol('bar'))
log(Symbol('fpp'))
Copy the code

_name: ‘Tom’ _name: ‘Tom

const name = Symbol('name')
const person = {
    [name]: 'Tom'._name: 'Tom' _name: 'Tom'
    say () {
        log(`The ${this[name]}`)
    }
}
log(person.name) // undefined
log(person.say()) // Tom
Copy the code

The main function of Symbol type data is to add a unique attribute name to the object

log(Symbol() = = =Symbol(), Symbol('foo') = = =Symbol('foo')) // false false
log(Symbol.for('foo') = = =Symbol.for('foo')) // true  
// Symbol maintains a descriptor to Symbol mapping table internally
log(Symbol.for(true) = = =Symbol.for('true')) // true  
// symbol.for () calls the toString() method internally
Copy the code

5. The Symbol() attribute is more appropriate as a private attribute of an object

const obj1 = {
    [Symbol()] :'Symbol value'[Symbol()] :'Symbol value'.foo: 'value'
}
for (key in obj1) { // foo
    log(key)
}
log(Object.keys(obj1)) // [ 'foo' ]
log(JSON.stringify(obj1)) // {"foo":"value"}

// Get the key values of all Symbol types for the object
log(Object.getOwnPropertySymbols(obj1)) // [ Symbol(), Symbol() ] 
Copy the code

for… In, object.keys (), json.stringify (), etc., cannot obtain the Symbol property, which proves that Symbol is more suitable as the private property of the Object.

ES6 iterable interface

Meaning of birth: In theory for… Of can iterate over any kind of data structure (arrays, pseudo-arrays, sets, maps, etc.)

const list1 = [1.2.3.4.5]
// const list1 = new Set([1, 2, 3, 4, 5])
for (const value of list1) {
    log(value)
    if (value > 2) {
        break}}// list1.some()
// list1.every()

const list2 = new Map()
list2.set({ a: 1 }, 1)
list2.set({ b: 2 }, 2)
for (const [key, value] of list2) {
    log(key, value)
}
Copy the code

2, Compare forEach and for… of

list2.forEach(item= > log(item)) // Do not break out of the loop
Copy the code

Data interface contains iterable interface –Symbol(symbol.iterator)

// const arr = [1, 2, 3, 4]
const arr = new Set([1.2.3.4])
log(arr[Symbol.iterator]) // [Function: values] defines an iterable Function on an array prototype object that returns an object
log(arr[Symbol.iterator]().next()) // {value: 1, done: false} calls the object's next() method
Copy the code

4. How to implement the iterable interface of the object, using the iterator pattern (design pattern)

const obj2 = {
    study: ['eat'.'sleep'.Big beans].life: ['travel'.'travel'.'food'].work: ['fishing'],
    [Symbol.iterator] () {
        const list = Object.entries(obj2)
        let index = 0
        return {
            next () {
                return { value: list[index], done: index++ >= list.length }
            }
        }
    }
}
// Use Symbol. Iterator to define the iterable interface of the object. of
for (const [key, value] of obj2) {
    log(key, value)
}
Copy the code

ES6 generator

1. General use

function* fn () {
    log('111... ')
    yield 100
    log('222... ')
    yield 200
}

const result = fn()
log(result.next())  / / 111... Return {value: 100, done: false}
log(result.next())  / / 111... Return {value: 200, done: false}
log(result.next())  {value: undefined, done: true}
Copy the code

2. Scenario requirements: To achieve a transmitter

function* createIdMaker () {
    let id = 1
    while (true) {
        yield id++
    }
}

const maker = createIdMaker()
log(maker.next().value)  // in ascending order
log(maker.next().value)
log(maker.next().value)
Copy the code

3. How to implement iterable interface of object, using generator

const obj2 = {
    study: ['eat'.'sleep'.Big beans].life: ['travel'.'travel'.'food'].work: ['fishing'],
    [Symbol.iterator]: function* () {
        const list = Object.entries(obj2)
        for (const item of list) {
            yield item
        }
    }
}

for (const item of obj2) {
    log(item)
}
Copy the code

ES7, ES8, and other new features

1, Object. Values (), the Object. The entries (), the Object. The getOwnPropertyDescriptors

const p1 = {
    firsetName: 'Yon'.lastName: 'zhang',
    get fullName () {
        return this.firsetName + ' ' + this.lastName
    }
}

log(Object.values(p1))  // ['Yon', 'zhang', 'Yon Zhang '] gets the set of object attribute values
log(Object.entries(p1))  // Get a collection of object attributes and values

const descriptors = Object.getOwnPropertyDescriptors(p1)
log(descriptors)
const p2 = Object.defineProperties({}, descriptors)
p2.firsetName = 'ton'
log(p2.fullName)
Copy the code

String extension methods padEnd() and padStart()

const books = {
    html: 3.css: 10.javaScript: 103,}for (const [key, value] of Object.entries(books)) {
    log(`${key.padEnd(16.The '-')} | ${value.toString().padStart(3.'0')}`)}// html------------ | 003
// css------------- | 010
// javaScript------ | 103
Copy the code