ECMAScript and JavaScript

We often hear ECMAScript and JavaScript, and in many cases we don’t know the difference between them, or even think they are equivalent. In fact, ECMAScript is also a scripting language and more generally a language specification, while JavaScrip can be regarded as an extension language of ECMAScript. ECMAScript only provides the most basic syntax, while JavaScrip implements the LANGUAGE standard of ECMAScript. And extended it. Thus, the relationship between ECMAScript and JavaScript is that the former is a specification of the latter and the latter is an implementation of the former (other ECMAScript dialects also include Jscript and ActionScript). Here is a diagram illustrating the relationship between ECMAScript and JavaScript: JavaScript = ECMAScript + BOM +DOM.

History of ECMAScript

As you can see, ES6 took 15 years from its inception to its final release. The most accurate version of ES6 is ECMAScript 2015(ES2015), but it is not named after the year, it is named after the version number, so it is also called ES6. So why is ES6 so important? ES6 is arguably the most important update to ECMAScript, so let’s take a look at what it does:

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

New features of ES2015(ES6)

1. Let the order

Let is used to declare variables. Its use is similar to var, but the declared variable is only valid within the code block in which the let command resides. Let’s take a look at its use and compare it to var:

Block-level scope

ES6 previously had only global and function scopes, but let actually added block-level scopes to JavaScript, eliminating the variable overwriting problem.

function f1() {
  var n = 5;
  if (true) {
    var n = 10;
  }
  console.log(n); / / 10
}

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); / / 5
}
Copy the code

There is no variable promotion

Unlike var, let does not have the phenomenon of “variable promotion”. The main purpose is to reduce runtime errors and prevent unexpected behavior by using a variable before it is declared. Therefore, variables must be used after the declaration, otherwise an error is reported.

console.log(foo); / / output is undefined
console.log(bar); / / error ReferenceError

var foo = 2;
let bar = 2;
Copy the code

Temporary dead zone

As long as the let command exists in the block-level scope, the variables it declares are “binding” to the region, no longer subject to external influence. The variable is not available until the let command declares it. This is grammatically called a “temporary dead zone”. The essence of a temporary dead zone is that the variable you want to use already exists as soon as you enter the current scope, but you can’t get it until the line of code that declared the variable appears.

for (var i = 0; i < 3; i++) {
  for (var i = 0; i < 3; i++) {
  }
  console.log( i) / / 3
}

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

Duplicate declarations are not allowed

Let does not allow the same variable to be declared twice in the same scope.

Function () {let a = 10; var a = 1; Function () {let a = 10; let a = 1; } function func(arg) { let arg; } function func(arg) {{let arg; // no error}}Copy the code

Properties of the top-level object

The top-level object refers to the Window object in the browser environment and the Global object in Node. In ES5, attributes of top-level objects are equivalent to global variables.

var a = 1; 
console.log(window.a) / / 1

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

The attributes of top-level objects are linked to global variables, which is considered one of the biggest design failures of the JavaScript language. There are several major problems with this design. First, there is no way to report an undeclared variable error at compile time, which is only known at run time (because global variables can be created by attributes of top-level objects, which are created dynamically). Second, it is easy for programmers to unknowingly create global variables (such as typos). Finally, the properties of the top-level object are read and written everywhere, which makes modular programming very difficult. On the other hand, the window object has an entity meaning, which refers to the browser window object, and the top-level object is an entity meaning object, which is also inappropriate.

In order to change this, ON the one hand, ES6 stipulates that, in order to maintain compatibility, global variables declared by var and function commands are still attributes of top-level objects. On the other hand, global variables declared by let, const, and class are not attributes of the top-level object. That is, starting with ES6, global variables will gradually be decoupled from the properties of top-level objects.

2. The const command

Const and let are essentially the same. Let has the same property as const, except that const declares a read-only constant. Once declared, the value of a constant cannot be changed. So we’ll only discuss where const is inconsistent with let

const a =1;
a=2; // TypeError: Assignment to constant variable.
Copy the code

In fact, a const declaration more specifically means that the address of the data is immutable. For primitive types, that means that the value is immutable. For complex types, that means that the reference address is immutable.

const foo = {};
foo.prop = 123; // Add a member attribute to foo. The reference address has not changed

foo = {}; // TypeError: "foo" is read-only (reference address changed, so this is not allowed)
Copy the code

3. Deconstructive assignment of variables

Destruct assignment of arrays

Any data structure that has an Iterator interface can be assigned in the form of an array.

var [a, b, c] = [1.2.3];
let [foo, [[bar], baz]] = [1The [[2].3]].let [ , , third] = ["foo"."bar"."baz"]; // third = "baz"
let [head, ...tail] = [1.2.3.4]; //head =1 tail = [2, 3, 4]
let [x, y, ...z] = ['a']; //a='a' y = undefined z=[]

var [foo = true] = []; // foo = true

//ES6 internally uses the strict equality operator (===) to determine whether a position has a value. Therefore, if an array member is not strictly equal to undefined, the default value will not take effect.
var [x = 1] = [undefined]; //x =1
var [x = 1] = [null];// x = null


let [x = 1, y = x] = [2];    // x=2; y=2
let [x = y, y = 1] = [];     // ReferenceError
Copy the code

Object destructuring assignment

var { foo, bar } = { foo: "aaa".bar: "bbb" };

let obj = { first: 'hello'.last: 'world' };
let { first: f, last: l } = obj; // Rename the variable

var {x = 3} = {};//x=3

var {x, y = 5} = {x: 1};//x=1 y=5

var {x:y = 3} = {};//y=3

var {x:y = 3} = {x: 5};//y=5
Copy the code

Destruct assignment of a string

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

let {length : len} = 'hello';
len / / 5
Copy the code

4. String extension

Iterator interface for strings

ES6 adds an Iterator interface to strings that can be used for… The of loop traverses.

for (let codePoint of 'foo') {
  console.log(codePoint)
}
Copy the code

at()

Given the string position, return the correct character.

'abc'.at(0) // "a"
'𠮷'.at(0) / / "𠮷"
Copy the code

startsWith(), endsWith()

  • StartsWith () : Returns a Boolean value indicating whether the parameter string is at the head of the source string.
  • EndsWith () : Returns a Boolean value indicating whether the parameter string is at the end of the source string.
var s = 'Hello world! ';

s.startsWith('Hello') // true
s.endsWith('! ') // true
Copy the code

repeat()

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

'x'.repeat(3) // "xxx"
'na'.repeat(0) / / ""
'na'.repeat(2.9) // The "nana" argument is rounded if it is a decimal.
'na'.repeat(Infinity)// If the RangeError argument is negative or Infinity, an error will be reported
'na'.repeat(-1)// If the RangeError argument is negative or Infinity, an error will be reported
'na'.repeat(-0.9) // "" But if the argument is a decimal between 0 and -1, it equals 0
'na'.repeat(NaN) // "" NaN is equal to 0
'na'.repeat('na') If the "" argument is a string, it is converted to a number first.
'na'.repeat('3') // If the "nanana" argument is a string, it is converted to a number first.
Copy the code

Template string

Template strings are enhanced strings, identified by backquotes (‘). It can be used as a regular string, it can be used to define multi-line strings, or it can be used to embed variables in strings.

const name = 'tom'
// You can insert an expression with ${}, and the result of the expression will be printed to the corresponding location
const msg = `hey, ${name} --- The ${1 + 2} ---- The ${Math.random()}`
console.log(msg)

const name = 'Tom'
const age = 18

  function fn(strArr,name,age){
    console.log(strArr,name,age) //[' Hello, my name is ', 'this year ','. '] Tom 18
    return strArr[0] +name+  strArr[1] + age + strArr[2]}let r = fn'Hello, my name is${name}This year,${age}. `
  console.log(r) // Hello, my name is Tom. I am 18 years old.
Copy the code

5. Array extensions

Array.from()

Two classes of objects are used to turn them into true arrays: array-like objects and iterable objects (including the new data structures Set and Map in ES6).

The so-called array-like object has only one essential feature, that is, it must have the length attribute. Therefore, any object with length can be converted to an Array by the array. from method, whereas the extension operator cannot.

Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
Array.from([1.2.3].(x) = > x * x) / / [1, 4, 9]
Array.from({ length: 3 });// [ undefined, undefined, undefined ]
Copy the code

Array.of()

Used to convert a set of values into an array.

Array.of(3.11.8) / /,11,8 [3]
Array.of() / / []
Array.of(undefined) // [undefined]

// Simulate the implementation
function ArrayOf(){
  return [].slice.call(arguments);
}
Copy the code

Find () and findIndex() of array instances

The find method of an array instance, used to find the first array member that matches the criteria. Its argument is a callback function that is executed by all array members until the first member that returns true is found, and then returned. If there is no qualified member, undefined is returned.

The findIndex method on an array instance is used much like the find method, returning the location of the first qualified array member, or -1 if all members fail.

Callbacks to the find and findIndex methods can take three arguments, the current value, the current position, and the original array.

[1.5.10.15].find(function(value, index, arr) {
  return value > 9;
}) / / 10

[1.5.10.15].findIndex(function(value, index, arr) {
  return value > 9;
}) / / 2

[NaN].indexOf(NaN)
// -1

[NaN].findIndex(y= > Object.is(NaN, y))
/ / 0
Copy the code

Fill () for array instances

The fill method fills an array with the given value.

['a'.'b'.'c'].fill(7)/ / (7, 7, 7)

new Array(3).fill(7)/ / (7, 7, 7)

// The fill method can also accept the second and third parameters that specify where the fill starts and ends.
['a'.'b'.'c'].fill(7.1.2)// ['a', 7, 'c']
Copy the code

Array instance keys()

Keys () is used to iterate over groups of numbers. Returns a traverser object, which can be used for… Keys () is the key name traversal

for (let index of ['a'.'b'].keys()) {
  console.log(index);
}
Copy the code

6. Object extension

A concise representation of the property

 let name = 'Tom'
  let fn =  function () {
    console.log("Fn")}let obj ={
    name,
    fn
  }
  console.log(obj.name)
  obj.fn()
Copy the code

Object.is()

Used to compare whether two values are strictly equal.

Object.is('foo'.'foo')
// true
Object.is({}, {})
// false

+0= = = -0 //true
NaN= = =NaN // false

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

Object.assign()

For merging objects, copy all enumerable properties of the source object to the target object.

var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
let obj = Object.assign(target, source1, source2);//obj===target {a:1, b:2, c:3}

Object.assign(undefined) / / an error
Object.assign(null) / / an error

let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true

Object.assign({ a: 'b'}, {[Symbol('c')]: 'd' }) // { a: 'b', Symbol(c): 'd' }

//Object.assign implements shallow copy, not deep copy.
// object. assign copies get a reference to this Object. Any changes to this object are reflected on the target object.
let obj1 = {a:1.b: {c:2}}
let obj2 = Object.assign({},obj1)
obj1.b.c =9
console.log(obj2.b.c) / / 9

//Object.assign treats the array as objects with attributes 0, 1, and 2, so attribute 4 of the target array overwrites attribute 1 of the original array.
Object.assign([1.2.3], [4.5]) / / [4, 5, 3]

Copy the code

Enumerability of a property

Each property of an object has a Descriptor that controls the behavior of the property. Object. GetOwnPropertyDescriptors (ES8) method can obtain the attribute description Object.

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
/ /}

Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false

Object.getOwnPropertyDescriptor([], 'length').enumerable
// false

// Enumerable is false for... In does not iterate over these two attributes inherited from the stereotype.

// All Class prototype methods are not enumerable.
Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
// false
Copy the code

Property traversal

  • for… in

    for... The in loop iterates over the object's own and inherited enumerable properties (excluding the Symbol property).Copy the code
  • Object.keys(obj)

    Keys returns an array containing all the enumerable properties (excluding Symbol properties) of the Object itself (excluding inheritance).Copy the code
  • Object.getOwnPropertyNames(obj)

    Object. GetOwnPropertyNames returns an array containing all attributes of the Object itself (excluding Symbol attribute, but cannot be enumerated attribute).Copy the code
  • Object.getOwnPropertySymbols(obj)

    Object. GetOwnPropertySymbols returns an array containing all the Symbol attribute of the Object itself.Copy the code
  • Reflect.ownKeys(obj)

    Reflects. ownKeys returns an array containing all the properties of the object itself, whether the property name is Symbol or string, and whether or not it is enumerable.Copy the code
const obj = {};
Object.defineProperties(obj, {
    property1: {enumerable: true.value: 1},
    property2: {enumerable: false.value: 2},Symbol("property3"] : {enumerable: true.value: 3},Symbol("property4"] : {enumerable: false.value: 4},
    10: {enumerable: true.value: 5},
    11: {enumerable: false.value: 6},
    "a": {enumerable: false.value: 7},
    "b": {enumerable: true.value: 8}});for(let key in obj){
  console.log(key) //10 property1 b
}
console.log(Object.keys(obj)); //["10", "property1", "b"]
console.log(Object.getOwnPropertyNames(obj));//["10", "11", "property1", "property2", "a", "b"]
console.log(Object.getOwnPropertySymbols(obj));//[Symbol(property3), Symbol(property4)]
console.log(Reflect.ownKeys(obj));//["10", "11", "property1", "property2", "a", "b", Symbol(property3), Symbol(property4)]
Copy the code

7. 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.

typeof Symbol(a)//"symbol"
Symbol() = =Symbol(a)//false

const name = Symbol(a)let obj = {
  [name]: "Tom"
}
obj[name] // 'Tom'
obj.name //undefined


The //Symbol value cannot be evaluated with other types of values and will report an error.
var sym = Symbol('My symbol');
"your symbol is " + sym // TypeError: can't convert symbol to string

//Symbol values can also be converted to Boolean values, but not numeric values.
var sym = Symbol(a);Boolean(sym) // true
Number(sym) // TypeError

// Sometimes we want to reuse the same Symbol value. The symbol.for method can do this
Symbol.for("bar") = = =Symbol.for("bar")//true

The // symbol. keyFor method returns the key of a registered Symbol type value.
var s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
Copy the code

8. Set and Map data structures

Set

ES6 provides a new data structure, Set. It is similar to an array, but the values of the members are unique and there are no duplicate values. The Set itself is a constructor used to generate the Set data structure. The Set function can take an array (or an array-like object) as an argument for initialization.

When you add a value to a Set, no type conversion occurs, so 5 and “5” are two different values.

  • Add (value) : Adds a value and returns the Set structure itself.
  • Delete (value) : deletes a value and returns a Boolean value indicating whether the deletion is successful.
  • Has (value) : Returns a Boolean value indicating whether the value is a member of Set.
  • Clear () : Clears all members with no return value.
// Array decrement
 Array.from(new Set([1.2.1.2.3])) / / [1, 2, 3]
 
 
 let s = new Set(a); s.add(1).add(2).add(2); //Set(2) {1, 2}
// Notice that 2 is added twice

s.size / / 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2);
s.has(2) // false
Copy the code

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.
  • 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. This feature means that a WeakSet member cannot be referenced, so a WeakSet is not traversal.

WeakSet can accept an array or array-like object as a parameter.

var ws = new WeakSet(a); ws.add(1); // TypeError: Invalid value used in weak set
ws.add(Symbol()); // TypeError: Invalid value used in weak set

var a = [[1.2], [3.4]];
ws.add(a); //WeakSet {Array(2), Array(2)}

var b = [3.4];
ws.add(b); //WeakSet {Array(2)}


var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window); // true
ws.has(foo);    // false
ws.delete(window);
ws.has(window);    // false
Copy the code

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.

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



var m = new Map(a);var o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false

//Map can also take an array as an argument
var map = new Map([['name'.'Joe'],
  ['title'.'Author']]); map.size/ / 2
map.has('name') // true
map.get('name') // "/"
map.has('title') // true
map.get('title') // "Author"

// If the same key is assigned more than once, the subsequent value overwrites the previous value.
let map = new Map(a); map .set(1.'aaa')
.set(1.'bbb');
map.get(1) // "bbb"

new Map().get('asfddfsasadf') //undefined

// The memory address is different
var map = new Map(a); map.set(['a'].555);
map.get(['a']) // undefined

let map = new Map(a); map.set(NaN.123);
map.get(NaN) / / 123
map.set(-0.123);
map.get(+0) / / 123
Copy the code

WeakMap

WeakMap structure is basically similar to Map structure, except that it only accepts objects as key names (except null) and does not accept values of other types as key names. Moreover, the objects that the key names refer to are not included in the garbage collection mechanism. WeakMap has only four methods available: get(), set(), has(), and delete().

9. Proxy

Proxy can be understood as a layer of “interception” before the target object. All external access to the object must pass this layer of interception. Therefore, Proxy provides a mechanism for filtering and rewriting external access. The word Proxy is used to mean that it acts as a Proxy for certain operations.

let obj ={b:2}
let proxy = new  Proxy(obj,{
  get(target, property,receiver){
    // Target is the object used to instantiate the Proxy,property is the name of the property to be obtained in the read operation, and receiver is the instantiated Proxy itself, i.e. Proxy.
    console.log(target, property,receiver,"get") //{b: 2, a: 1} "a" Proxy {b: 2, a: 1} "get"
   // return target[property] // Returns the value as the access value

   //Reflect encapsulates a set of operations on objects internally, so we can call Reflect after implementing our own logic
   return Reflect.get(target, property,receiver)
  },
  set(target, property, value,receiver){
    console.log(target, property, value,receiver,"set") //{b: 2} "a" 1 Proxy {b: 2} "set"
    // target[property] = value
    // return true
    return Reflect.set(target, property, value,receiver)
  },
  deleteProperty(target,property){
    console.log(target, property,"deleteProperty") //{b: 2} "a" "deleteProperty"
    // delete target[property]
    return Reflect.deleteProperty(target,property)
  }
})
proxy.a =1
console.log(proxy.a) / / 1
delete proxy.a
console.log(proxy.a) //undefined
Copy the code
  1. The Iterator and for… Of circulation

Iterator provides a unified and simple interface for accessing various data structures. Second, the members of the data structure can be arranged in a certain order. Third, ES6 created a new traversal command for… The of loop is an Iterator interface for… Of consumption. In short, any data that provides an Iterator interface can be used for… Of traversal.

Of our arrays, objects, maps, and sets, only objects do not have an Iterator interface deployed, and therefore cannot be used for… Of traversal.


const obj = { foo: 123.bar: 456 }
for (const item of obj) { Obj is not iterable
  console.log(item)
}

// Next we deploy Iterator for obj so that it can be traversed
obj[Symbol.iterator ] = function(){
  let index = 0
  const key = Object.keys(this);
  return{
    next:function(){
      returnindex<key.length? {value:obj[key[index++]],done:false}, {value:undefined.done:true}}}}// Print it
for (const item of obj) { / / 123 456
  console.log(item)
}
Copy the code

New features of ES2016(ES7)

1. Exponentiation operator (**)

Math.pow(3.2) = = =3支那2    / / 9
Copy the code

2. Includes ()

  • Includes () : Returns a Boolean value indicating whether the parameter string was found.
[1.2.3].indexOf(3) > -1 // trueEquivalent to: [1.2.3].includes(3) // true

[1.2.NaN].includes(NaN)     // true
[1.2.NaN].indexOf(NaN)  // -1
Copy the code

New features of ES2017(ES8)

1. Array instance entries() and values()

Entries () and values() — Used to iterate through groups of numbers. They both return a traverser object, which can be used for… The of loop is traversed, the only difference being that values() is traversal of key values and entries() is traversal of key value pairs.


for (let elem of ['a'.'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a'.'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"
Copy the code

2.Object.getOwnPropertyDescriptors

The description of the Object. GetOwnPropertyDescriptors method can obtain the attribute Object.

const obj = {
  foo: 123.get bar() { return 'abc'}};Object.getOwnPropertyDescriptors(obj)
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
Copy the code

3. PadStart (), padEnd ()

ES8 introduces the function of string completion length. If a string is not of a specified length, the header or tail is completed. PadStart is used for head completion and padEnd for tail completion.

'x'.padStart(5.'ab') // 'ababx'
'x'.padStart(4.'ab') // 'abax'

'x'.padEnd(5.'ab') // 'xabab'
'x'.padEnd(4.'ab') // 'xaba'
Copy the code

4. Async and await asynchronous solutions

console.log('A')
setTimeout(() = >console.log('B'),1000)
const start = new Date(a)while(new Date- start<3000) {}console.log("C")
setTimeout(() = >console.log('D'),0)
new Promise((resolve,reject) = >{
  console.log('E')
  foo.bar(100)
})
.then(() = >console.log("F"))
.then(() = >console.log("G"))
.catch(() = >console.log("H"))
console.log('I')
//ACEIHBD
Copy the code

The six appendices

ES6 Introduction