ECMAScript

Article content output source: pull hook education front-end high salary training camp

ECMAScript is a scripting language, commonly abbreviated ES, and is often seen as a standard specification for JavaScript. JavaScript is actually an extension of ECMAScript. Because ECMAScript only provides the most basic syntax, specifying how code should be written, such as how to define variables and functions, it only stays at the language level and cannot be directly used to complete the actual function development in applications. JavaScript, which we often use, implements the ECMAScript language standard and extends it to allow us to operate DOM and BOM in the browser environment and read and write files in the Node environment.

JavaScript in the browser is ECMAScript plus the web API (DOM and BOM). JavaScript in the Node environment is ECMAScript plus the set of apis provided by Node. Apis provided by built-in modules such as FS or NET. So the Javascript language itself refers to ECMAScript.

Since 2015, ES has maintained a large version of the iteration every year. Along with the iteration of these new versions, many new features have emerged successively, which leads to the JavaScript language itself becoming more and more advanced and convenient.

The figure shows the name, version number, and release date of each iteration of ECMAScript. From ES5 to ES2015, it is the golden period of front-end development, during which many subverting new functions have been added, which has greatly changed compared to the previous period. Since ES2015, we have started to iterate every year, in line with the current spirit of Internet taking small steps, and we have started to name ourselves according to the year instead of the version number. Many people also refer to ES2015 as ES6, but many people use ES6 to refer to all the new standards in general.

See the ECMAScript standard specification www.ecma-international.org/ecma-262/6….

Here’s a breakdown of the new ES6 features.

  • Solve some problems or deficiencies in the original grammar
  • The original syntax is enhanced
  • New object, new method, new function
  • New data types and data structures

let const

Scope – The scope within which a member can act.

Prior to ES2015, there were only two types of scope in ES, global scope and function scope. Block-level scopes have been added in ES2015. Refers to scopes enclosed in {}, such as the parts of the if statement and for loop statements enclosed in {} parentheses.

Previously, blocks had no separate scope, so they could be accessed outside members defined in the block. Eg:

if(true){
  var foo = 'aaa'
}
console.log(foo) // aaa
Copy the code

let

If you declare a variable using let, it can only be accessed in the declared block.

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

This means that members declared in a block are not externally accessible.

Variables declared by let cannot be promoted.

Console. log(foo) var foo = 'aaa' console.log(bar) // console error let bar = 'bar'Copy the code

const

Const declares a read-only constant/constant. Just add a read-only on top of let.

Best practice: Use const instead of var, with let.

conclusion

  • Variables declared by let and const are accessible only within the declared block, not externally
  • Variables declared by let and const are not promoted
  • Variables declared by let and const cannot be declared more than once in the same scope
  • A variable declared by const cannot be modified

Array deconstruction

ES2015 adds a new method for quickly retrieving elements from arrays and objects, called deconstruction.

Array structure:

Const arr = [100, 200, 300] // Const [foo, bar, baz] = arr console.log(foo, bar, baz) // 100 200 300 // Const [, f] = arr console.log(f) // 300 // Extract all members from the current position in an array //... Const [a,...rest] = arr console.log(rest) // [200, 300] // If the variables are less than the length of the array, they are extracted in order, Const [y] = arr console.log(y) // 100 // If the variable is longer than the array length, // Undefined const [z, x, c, v] = arr console.log(v) // Undefined const [z, x, c, v] = arr console.log(v) Const [q, w, e = 1, r = 2] = arr console.log(e, r) // 300 2Copy the code

Object deconstruction

Object deconstruction is extracted by attribute names.

Usage:

const obj = { name: 'aaa', age: 18} const {name} = obj console.log(name) const age = 20 objAge = 33 } = obj console.log(age, objAge) // 20 18Copy the code

Template string literal

const name = 'es2015'
const str = `hello ${name},this is a \'string\'`
console.log(str) // hello es2015,this is a 'string'
Copy the code
// We can add a tag function to the template string const STR = console.log 'hello world' // ['hello world'] const name = 'Tom' const gender = true // // The first argument of the tag function is the array of static contents of the template string divided by the expression. // The following argument is the variable of the expression that appears in the template string. // The return value is the final content of the string function tag1(string, name, gender) { console.log(string) // [ 'hey, ', ' is a ', '' ] console.log(name, gender) // tom true const sex = gender ? 'man' : 'woman' return string[0] + name + string[1] + sex + string[2] } const str1 = tag1`hey, ${name} is a ${gender}` console.log(str1) // hey, tom is a manCopy the code
  • Traditional strings do not support line breaks. Template strings do
  • Template strings support embedded variables, rather than string concatenation
  • Template strings can be manipulated using tag functions

String extension methods

  • Includes () looks up whether a character is included in the string
  • StartsWith () specifies whether the string startsWith a character
  • EndsWith () specifies whether the string endsWith a character
const message = 'Error: foo is not defined.'
console.log(message.startsWith('Error')) // true
console.log(message.endsWith('.'))  // true
console.log(message.includes('foo'))  // true
Copy the code

Extension of a function

Parameter Default Value

Function foo(enable) {enable = enable === undefined? true : Log (enable)} // Now you just need to set a = after the parameter to set the default value // this default value is used when no argument is passed or the argument is undefined. Function foo(bar, enable = true) {console.log(bar, enable) // 111 true} foo(111)Copy the code

The remaining parameters

Function foo() {console.log(arguments)} function foo() {console.log(arguments)} function foo() {console.log(arguments)} // The parameter takes all arguments from the current position forward as an array // Only the last of the parameters can appear, and only once can function foo(first,... args) { console.log(args) } foo(1, 2, 3, 4)Copy the code

An array of

Const arr = ['foo', 'bar', 'baz'] console.log. Apply (console, arr) // es2015 console.log(... Arr) // es2015 post // foo bar bazCopy the code

Arrow function

  • Short and easy to read
const inc = n => n + 1
console.log(inc(100))
Copy the code
  • It doesn’t change the this point
const foo = {
  name: 'tom',
  sayName: function () {
    console.log(this.name)
  },
  sayName1: () => {
    console.log(this.name)
  },
  sayNameAsync: function () {
    setTimeout(() => {
      console.log(this.name)
    })
  }
}
foo.sayName() // tom
foo.sayName1() // undefined
foo.sayNameAsync() // tom
Copy the code

Object extension

Enhancements to object literals

Const bar = '456' const obj = {foo: 123, const bar: bar // es2015 // method1: function(){} Method1 (){}, method1() {}, method1() {}, method1() {}, method1() {}, method1() {}, method1() {}, method1(); Obj [] = 1 + 1:456,} obj[] = 123Copy the code

Object extension method

  • Object.assign() copies attributes from multiple source objects to a target Object. If there are identical attributes, the attributes in the source Object overwrite the attributes in the target Object. The following object overwrites the preceding object
const source1 = {
  a: 123,
  b: 123
}
const source2 = {
  b: 789,
  d: 789
}

const target = {
  a: 456,
  c: 456
}
const result = Object.assign(target, source1, source2)
console.log(target)  // { a: 123, c: 456, b: 789, d: 789 }
console.log(result === target) // true
Copy the code
  • Object.is() determines whether two values are equal
console.log(0 == false)  //true
console.log(0 === false) // false
console.log(+0 === -0) // true
console.log(+0 === -0) // true
console.log(NaN === NaN) // false

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

Proxy Proxy object

If you want to monitor the read and write of attributes in an Object, you can use object.defineProperty in ES5 to add attributes to the Object so that you can capture the read and write of attributes in the Object. This method is very widely used, vue3.0 before the implementation of this method of data response, so as to achieve two-way data binding.

In ES2015, there is a new type called Proxy, which is used to set the access Proxy for objects. Proxy can be used to easily monitor the read and write process of objects. It is more powerful and easier to use than Object.defineProperty.

const person = { name: 'aaa', age: 20} // create a Proxy instance, the first parameter is the object to operate on // the second parameter is also an object - the Proxy processing object // monitor property access through the get method, Const personProxy = new Proxy(person, {// get receives parameters as follows: Get (target, property) {// console.log(target, property) // {name: 'aaa', age: 20} name // return 'zhangsan' // if target has current property, return undefined or default value return property in target? target[property] : 'default'}, // set method argument: Set (target, property, value) {// console.log(target, property, value) // {name: 'aaa', age: 20 } gender true if (property === 'age') { if (! Number.isInteger(value)) { throw new TypeError(`${value} is not an int`) } } target[property] = value } }) console.log(personProxy.name) // aaa console.log(personProxy.xxx) // default personProxy.gender = true // personProxy.age = '100' // TypeError: 100 is not an int personProxy.age = 100 console.log(person) // { name: 'aaa', age: 100, gender: true }Copy the code

Proxy vs. Object.defineProperty

  • DefineProperty can only monitor reads and writes of attributes, Proxy can monitor more object operations such as EG: delete operations, calls to methods in objects, etc.
const person = { name: 'aaa', age: 20} const personProxy = new Proxy(person, {const personProxy = new Proxy) DeleteProperty (target, property){console.log(target, property) // {name: 'aaa', age: 20 } age delete target[property] } }) delete personProxy.age console.log(person) // { name: 'aaa' }Copy the code
  • Proxy better supports array object monitoring
const list = [] const listProxy = new Proxy(list, { set(target, property, value) { console.log('set', property, // set 0 100 target[property] = value return true}}) listProxy.push(100) console.log(list) // [100]Copy the code
  • Proxy regulates reads and writes of objects in a non-intrusive manner

Reflect

Reflect is a unified object manipulation API provided in ES2015. Reflect belongs to a static class and cannot instantiate an object with a new method. It can only call static methods in a static class, eg: reflect.get ().

Reflect internally encapsulates a series of low-level operations on objects, providing 14 methods to manipulate objects, one of which is deprecated. The remaining 13 correspond to the methods in Proxy. The Reflect member method is the default implementation of the Proxy handling object method inside.

Const obj = {foo:'123', bar:'456'} const proxy = new proxy (obj,{ property){ return Reflect.get(target,property) } })Copy the code

Why should we have a Reflect object

Provide a uniform set of apis for manipulating objects.

In the past, you might have used methods on objects or operators like DELETE or in to manipulate objects, which would have been confusing for beginners. Reflect is to unify the way an object operates.

const obj = { name: 'aaa', age: Log ('age' in obj)// Whether an attribute exists console.log(delete obj['age'])// Delete attribute Console. log(object.keys (obj))// Get the attribute name // 'name')) console.log(Reflect.deleteProperty(obj, 'age')) console.log(Reflect.ownKeys(obj))Copy the code
  1. Reflect.get(target, name, receiver)

Find and return the name property of the target object. Undefined is not returned.

const obj = {
  name: 'aaa',
  age: 18
}
console.log(Reflect.get(obj, 'name')) // aaa
Copy the code

If the name attribute deploys a getter, the function’s this binding receiver is read.

var myObject = { foo: 1, bar: 2, get baz() { return this.foo + this.bar; }}; var myReceiverObject = { foo: 4, bar: 4, }; Reflect.get(myObject, 'baz', myReceiverObject) // 8Copy the code
  1. Reflect.set(target, name, value, receiver)
const obj = {
  name: 'aaa',
  age: 18
}
Reflect.set(obj, 'gender', 'man')
console.log(obj) // { name: 'aaa', age: 18, gender: 'man' }
Copy the code
  1. Reflect.has(obj, name)

Corresponds to the in operator in name in obj. Indicates whether the obj object has a name attribute.

  1. Reflect.deleteProperty(obj, name)

Equivalent to delete obj[name], used to delete the attributes of an object

  1. Reflect.construct(target, args)

Equivalent to new Gouzao(… args)

function Person(name){
  this.name = name
}

// new
const person1 = new Person('zhangsan')

// Reflect.construct
const person2 = Reflect.construct(Person, ['zhangsan'])
Copy the code
  1. Reflect.getPrototypeOf(obj)

Used to read the __proto__ property of an Object, corresponding to Object.getProtoTypeof (obj)

const myObj = new FancyThing(); GetPrototypeOf (myObj) === FancyThing. Prototype; // Reflect. GetPrototypeOf (myObj) === FancyThing. Prototype;Copy the code
  1. Reflect.setPrototypeOf(obj, newProto)

Object. SetPrototypeOf (obj, newProto)

const myObj = {}; SetPrototypeOf (myObj, array.prototype); // Reflect. SetPrototypeOf (myObj, array.prototype); myObj.length // 0Copy the code
  1. Reflect.apply()

  2. Reflect.defineProperty(target, propertyKey, attribute)

Basically equivalent to Object.defineProperty, used to define attributes for objects.

10.Reflect.getOwnPropertyDescriptor(target, PropertyKey) Reflect. GetOwnPropertyDescriptor basic equivalent to the Object. GetOwnPropertyDescriptor, used to get the description of the specified attribute Object

  1. Reflect.isExtensible (target)

The reflect. isExtensible method corresponds to object. isExtensible, which returns a Boolean value indicating whether the current Object isExtensible.

12. Reflect. PreventExtensions (target) Reflect. PreventExtensions corresponding to the Object. PreventExtensions method, is used to make an Object into an extension

  1. Reflect.ownKeys(target)

Returns all properties of an object

Promise

Class class

// By defining a function, Function Person(name){this.name = name} person.prototype. say = function(){console.log(' hi, ${this.name} ')} // es2015 class Person {// constructor is the constructor(name) { this.name = name } say() { console.log(`hi, my name is ${this.name}`) } } const p = new Person('tom') p.say()Copy the code

A static method

Methods within a type are generally divided into instance methods and static methods. Instance methods are called from an instance of the type; static methods are called directly from the type.

When using a function to define a type, static methods can be defined directly inside the function. In ES2015, static keywords are added to add static members. If a static method defined using static has this, it refers to the type, not the instance.

Class Person {constructor(name) {this.name = name} class Person {constructor(name) {this.name = name Person(name)}} // Use the type directly to call the static method person.create (' Tom ')Copy the code

Inheritance extends

Inheritance is a very important feature in object orientation, through which you can abstract out the repetition between similar types. Prior to ES2015, inheritance was mostly implemented using archetypes. In ES2015, inheritance is implemented using extends.

class Person { constructor(name) { this.name = name } say() { console.log(`hi, My name is ${this.name} ')}} Class Student extends Person {constructor(name,number){// Super always points to the parent class. Super (name) this.number = number} hello(){// You can use the super object to access the super.say() console.log(' my school ') member number is ${this.number}`) } } const s = new Student('jack', '100') s.hello() // hi, my name is jack // my school number is 100Copy the code

Set data structure

Es2015 provides a new data structure called sets, which can be understood as collections. It is similar to a traditional array, except that the members of a Set cannot be repeated.

Const s = new Set() const s = new Set() const s = new Set() This add is ignored s.a dd (1). The add (2). The add (3). The add (2) the console. The log (s) / / Set (3) {1, 2, // forEach(v => console.log(v)) // 1 2 3 // forEach(v => console.log(v)) // 1 2 3 // forEach(v => console.log(v)) // 1 2 3 // forEach(v => console.log(v)) // 1 2 3 // forEach(v => console.log(v)) // 1 2 3 // forEach(v => console.log(v)) of...) For (let I of s) {console.log(I)} // 1 2 3 Console. log(s.haas (2)) // delete the data in the set. If the data is deleted successfully, return true Console. log(s.delte (1)) // clear() console.log(s) // Set(0) {} const arr = [1, 2, 1, 3, 4, 2] // An instance of Set takes an array of values as its initial value, // Result = array. from(new Set(arr)) const result = [...new Set(arr)] console.log(result) // [ 1, 2, 3, 4 ]Copy the code

Map data structure

A Map data structure is similar to an object in that it is a collection of key-value pairs. However, the keys in an object structure can only be strings, causing problems when storing complex data. The only difference between a Map and an object is that it can be used as keys of any type.

// Create an instance of Map with new const m = new Map() const Tom = {name: 'Tom'} const jack = {name: 'jack'} // You can use the set method of the instance to set the key-value pair for the Map instance m.sat (Tom, 90) m.sat (Jack, 95) console.log(m) // Map(2) {{name: 'tom' } => 90, { name: 'Jack'} => 95} // get gets the value of an attribute console.log(m.git (Tom)) // 90 // has determines whether an attribute exists ForEach ((value, key) => {console.log(value, key) => {console.log(value, key); key) // 95 { name: 'jack' } }) for (let i of m) { console.log(i) // [ { name: 'jack' }, 95 ] }Copy the code

Symbol

Prior to ES2015, the attribute names of objects were strings, and strings could be repeated, resulting in conflicts. If both a.js and B. js refer to a cache object in a shared.js file, file A adds attribute foo to cache and file B adds attribute foo to cache, causing a collision.

In the past, the solution was convention, such as a file named with ‘a_’ and b file named with ‘b_’. But the agreed way only circumvents the problem, it does not solve the problem, if someone does not follow the agreement, the problem will still occur.

// shared.js ==========================
const cache = {}

// a.js ==============================
cache['foo'] = Math.random()
cache['a_foo'] = Math.random()
// b.js ==============================
cache['foo'] = '123'
cache['b_foo'] = '123'

console.log(cache) // { foo: '123' }
Copy the code

In order to solve this problem, ES2015 proposed a new data type Symbol, which represents a unique value.

Use the Symbol function to create a Symbol typeof data, and use typeof to print the result is Symbol, indicating that Symbol is a data type. The best feature of this data type is that it is unique. Each value created through the Symbol function is unique and never repeated.

For debugging purposes during development, the Symbol function allows you to pass in a string as the descriptive text for this value, which Symbol can be distinguished from the console in cases where Symbol is used multiple times.

Since ES2015, objects can use values of type Symbol as attribute names, so object attribute names can now be of two types, String and Symbol.

Const s = Symbol() console.log(s) // Symbol() console.log(typeof s) // Symbol() console.log(typeof s) // Symbol console.log(Symbol() === Symbol()) // false console.log(Symbol('foo')) // Symbol(foo) console.log(Symbol('bar')) // Symbol(bar) const obj = { [Symbol()]: '789' } obj[Symbol()] = '123' obj[Symbol()] = '456' console.log(obj) // { [Symbol()]: '789', [Symbol()]: '123', [Symbol()]: '456' }Copy the code

You can use Symbol to simulate the implementation of private members of objects. In the past, private members were defined by convention. For example, the beginning of a convention is a private member, and external members can not access the beginning of a private member. We can now use Symbol directly:

// use Symbol to create the attribute name of the private member // a.js ======================= // Use Symbol to create the attribute name of the private member // Inside the object, use Symbol to get the corresponding attribute member const name = Symbol() const person = { [name]:'aaa', Say () {the console. The log (this [name])}} / / b.j s = = = = = = = = = = = = = = = = = = = = = = = / / in the external unable to create the same Symbol, so I can't have direct access to the members of the Symbol attributes, Only members of a common noun can be called person.say() /// aaaCopy the code

Symbol’s main function is to add unique attribute names to objects.

supplement

  • The Symbol function creates a unique value, even if the same parameter is passed.
console.log(Symbol('foo') === Symbol('foo')) // false
Copy the code
  • If you want to reuse the same Symbol value globally, you can do so as a global variable, or you can use symbol.for ().

The symbol.for () method passes a string. Passing the same string returns the same Symbol value.

This method internally maintains a global registry that provides a one-to-one correspondence between strings and Symbol values. If the for method is not passed as a string, it will be converted to a string.

const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2) // true
console.log(Symbol.for(true) === Symbol.for(true))
Copy the code
  • Symbol has many Symbol constants built in to serve as internal method identifiers that allow JS objects to implement some of the built-in interfaces.
console.log(Symbol.iterator) // Symbol(Symbol.iterator)
console.log(Symbol.hasInstance) // Symbol(Symbol.hasInstance)
Copy the code

For example, if we define an obj object and call the object’s toString() method, the result will be object object by default. We call such a string the toString tag of the object. If we want to customize the toString tag of the object, We can add specific members to the object to identify it. ECMAScript requires us to implement the interface using the Symbol value, considering that adding such identifiers using strings could duplicate internal members.

Add a Symbol. ToStringTag to the object and make it equal to ‘XObject’. The toString method prints XObject.

const obj = {
  [Symbol.toStringTag]: 'XObject'
}
console.log(obj.toString()) // [object XObject]
Copy the code
  • The Symbol attribute defined in the Object is not available through the for in loop, nor through the object.keys () method. If we serialize the Object with json.stringify (obj), Symbol is ignored. These attributes make the value of the Symbol attribute particularly suitable as a private property. Want to get the Symbol attribute name can use Object. * * getOwnPropertySymbols () method, * * Object can only access all the Symbol in the type of attribute names

for… Of circulation

There are many ways to iterate over arrays in ECMAScript

  • For loop, suitable for traversing ordinary arrays
  • for… In loop, suitable for traversing key value pairs
  • A traversal method for some objects, eg: forEach

These traversal methods have certain limitations, so ES2015 introduced a new for… Of circulation. This approach will later be used as a unified way to traverse all data structures.

  • for… The of loop can be terminated with a break
  • Pseudo-arrays, Set instances, Map instances can also use for… Of traversal
  • Unable to traverse ordinary objects

可迭代

There are more and more structured data types in ES: Object, Array, Ser, Map… Es2015 provides the Iterable interface to provide a uniform way to traverse a wide variety of data structures. Implementing the Iterable interface is for… The premise of.

// 实现可迭代接口(Iterable)
const obj = {
  store: [1, 2, 3],
  [Symbol.iterator]: function () {
    let i = 0
    const self = this
    return {
      next: function () {
        return {
          value: self.store[i],
          done: i++ >= self.store.length
        }
      }
    }
  }
}

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

Generator

function* foo() {
  console.log('111')
  yield 100
  console.log('222')
  yield 200
}
const result = foo()
console.log(result.next()) // 111 { value: 100, done: false }
console.log(result.next()) // 222 { value: 200, done: false }
Copy the code

ES Modules

ES2016

ES2016 has two new methods.

  • Array.prototype.includes()

ES2016 looks for an element in the array that uses the indexOf method. This method returns -1 if it does not exist. It does have a place to return it, but it cannot be used to look for NaN. The includes method makes up for this shortcoming and can be used to find out if NaN exists, returning true or false.

  • The exponential operator **

Before ES2016, we used math.pow (3, 2) to calculate 10. ES2016 added the exponent operator **, console.log(3 ** 2) to get 9.

ES2017

  • Object.values() retrieves all the values of the Object, and the corresponding object.keys () method retrieves all the keys of the Object.
  • The object.entries () method obtains an array of key-value pairs for an Object
const obj = { a: 1, b: 2 }
console.log(Object.entries(obj))  // [ [ 'a', 1 ], [ 'b', 2 ] ]
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value)
  // a 1
  // b 2
}
console.log(new Map(Object.entries(obj))) // Map(2) { 'a' => 1, 'b' => 2 }
Copy the code
  • Object. GetOwnPropertyDescriptors () for a complete description of the Object attribute information

  • String. The prototype. PadStart (num, STR)/String. Prototype. PadEnd filling the original with specified String String the beginning or end, know to specified digits

console.log('wl'.padEnd(10, '----------')) // wl--------
console.log('102'.padStart(4, '0')) // 0102
Copy the code
  • You can add a trailing comma to a function argument
function(
  a,
  b,
) {

}
Copy the code
  • Async / Await