Introduction to ECMAScript6


foreword

Long time no see. I have been busy writing projects for a while, and have no time to write a blog. Now I finally have time to write an article about the basics of ECMAScript6. If you think this article is helpful to you, please support the blogger three times, thank you very much.
insert image description here


以下是本篇文章正文内容

1. Introduction to ECMAScript6

1. The relationship between ECMAScript and JavaScript

A common question is, what is the relationship between ECMAScript and JavaScript?

The relationship between ECMAScript and JavaScript is 前者是后者的规格,后者是前者的一种实现(other ECMAScript dialects include JScript and ActionScript). In everyday situations, the two terms are interchangeable.


2、ECMAScript6?

ES6 is not only a historical term, but also a general reference. It means the next-generation standard of JavaScript after version 5.1, covering
ES2015, ES2016, ES2017, etc., while ES2015 is the official name, specifically referring to the language of the official version released that year standard.

ES6 —> June 2015 ES6.0
Every June, release a version
June 2016 ES6.1 ES7 ES2016
June 2017 ES6.2 (async await) ES8 ES2017
ESnext: 'next generation js' language

ES6 environment:
webpack3.x
Traceur


2. New command

1、let

ES6 has added let命令, 用来声明变量。它的用法类似于var, but the declared variables are only in let命令所在的代码块内有效. In the code block below, two variables are declared with let and var respectively. Then call these two variables outside the code block. As a result, the variable declared by let reports an error, and the variable declared by var returns the correct value. This shows that the variable declared by let is only valid in the code block where it is located.

{
    
    
  let a = 10;
  var b = 1;
}
console.log(b); // 1
console.log(a); // 报错a没有定义

for循环的计数器, it is very suitable to use the let command. The counter i is only valid in the body of the for loop, and an error will be reported if it is referenced outside the loop.

If the following code uses var, the final output is 10. Because the variable i is declared by the var command, it is valid in the global scope. The value of the variable i will change every time the loop is executed, and the console.log(i) inside the function assigned to the array a in the loop, the i inside It points to the global i. That is to say, the i in all the members of the array a points to the same i, which causes the value of i in the last round to be output at runtime, which is 10.

If you use let, the declared variable is only valid in the block-level scope, and the final output is 6. Because the variable i is declared by let, the current i is only valid in the current cycle, so the i in each cycle is actually a new variable, so the final output is 6. Since the JavaScript engine internally remembers the value of the previous cycle, when initializing the variable i of the current cycle, it calculates on the basis of the previous cycle:

var a = [];
for (var i = 0; i < 10; i++) {
    
    
  a[i] = function () {
    
    
    console.log(i);
  };
}
a[6](); // 10
 
var a = [];
for (let i = 0; i < 10; i++) {
    
    
  a[i] = function () {
    
    
    console.log(i);
  };
}
a[6](); // 6

let does not allow repeated declaration of the same variable in the same scope, and cannot redeclare parameters in the same module scope inside the function.

let a = 10;// 即使声明是var a = 10;后面一样报错
let a = 1;// 报错
 
function func(arg) {
    
    
  let arg; // 调用时因同范围重名报错
}
 
function func(arg) {
    
    
  {
    
    
    let arg; // 不报错,因为对上一个arg来看在子模块中
  }
}

In addition, there is another special feature of the for loop, that is, the part where the loop variable is set is a separate parent scope, and the inside of the loop body is a child scope:

let i = 123;
console.log(i);
for (let i = 0; i < 2; i++,console.log(i)) {
    
    
  let i = 'abc';
  console.log(i);
}
// 123
// abc
// 1
// abc
// 2

var命令会发生“变量提升”现象, that is, the variable can be used before the declaration, and the value is undefined. In order to correct this phenomenon, the let command changes the grammatical behavior, and the variables it declares must be used after the declaration, otherwise an error will be reported. This is syntactically, 称为“暂时性死区”``(temporal dead zone,简称TDZ). For example: adding a sentence of typeof x before let x will report an error, because the scope of the same block is before let x, and x cannot perform any operations.

let actually adds a new block-level scope to JavaScript. Outside the scope surrounded by {}, it is not affected by the inner let variable (but will be affected by the "variable promotion" of var):

function text1(){
    
    
  let n = 5; //或var n = 5;
  if (true) {
    
    
    let n = 10;
  }
  console.log(n); // 5
}
 
function text2(){
    
    
  var n = 5;
  if (true) {
    
    
    var n = 10;
  }
  console.log(n); // 10
}
 
function text3(){
    
    
  let n = 5;
  if (true) {
    
    
    var n = 10; //报错,已经声明了n
  }
}

2、const

const declares a read-only constant. Once declared, the value of the constant cannot be changed, and must be initialized immediately when declared, and cannot be left for later assignment. The scope of const is the same as the let command: it is only valid in the block-level scope where the declaration is located.

What const actually guarantees is not that the value of the variable cannot be changed, but that the memory address pointed to by the variable cannot be changed. For simple types of data (numbers, strings, Boolean values), the value is stored at the memory address pointed to by the variable, so it is equivalent to a constant. But for composite types of data (mainly objects and arrays), the memory address pointed to by the variable is only a pointer. const can only guarantee that the pointer is fixed. As for whether the data structure it points to is variable, it is completely out of control. Therefore, one must be very careful about declaring an object as a constant.

const foo = {
    
    }; // const foo = []同理,可以正常使用push等功能
foo.prop = 123; // 为foo添加一个属性,可以成功
console.log(foo.prop); //123
foo = {
    
    }; // 将foo指向另一个对象,就会报错

If you really want to freeze an object or object properties, you should useObject.freeze方法


3、class

ES6 provides a way of writing closer to traditional languages, introducing the concept of Class (class) (the data type of a class is a function, and the class itself points to a constructor) as an object template. With the class keyword, a class can be defined. Class can be regarded as just a syntactic sugar. Most of its functions can be achieved by ES5. The new class writing method only makes the object prototype writing method clearer and more like the syntax of object-oriented programming:

function Point(x, y) {
    
    
  this.x = x;
  this.y = y;
}
Point.prototype.toString = function () {
    
    
  return '(' + this.x + ', ' + this.y + ')';
};
 
// 上面为原先写法,下面为ES6的Class写法
 
class Point {
    
    
  constructor(x, y) {
    
      // 构造方法,this关键字代表实例对象
    this.x = x;
    this.y = y;
  }
  toString() {
    
     // 自定义方法,方法之间不需要逗号分隔,加了会报错
    return '(' + this.x + ', ' + this.y + ')';
  }
}

The prototype property of the constructor continues to exist on ES6 classes. In fact, all methods of a class are defined on the prototype property of the class. But all methods defined inside the class are non-enumerable:

class Point {
    
    
  constructor() {
    
    
  }
  toString() {
    
    
  }
  toValue() {
    
    
  }
}
console.log(Object.keys(Point.prototype)); // [] 不可枚举
console.log(Object.getOwnPropertyNames(Point.prototype)); // ["constructor", "toString", "toValue"]
 
// 相当于
 
function Point() {
    
    
}
Point.prototype = {
    
    
  constructor() {
    
    },
  toString() {
    
    },
  toValue() {
    
    },
};
console.log(Object.keys(Point.prototype)); // ["constructor", "toString", "toValue"]

The attribute name of the class can be an expression:

let methodName = 'getArea';
class Square {
    
    
  [methodName]() {
    
    
  }

Like functions, classes can also be defined in the form of expressions. The following code defines a class using expressions. It should be noted that the name of this class is MyClass instead of Me. Me is only available in the internal code of Class and refers to the current class:

const MyClass = class Me {
    
     // 如果类的内部没用到的话,可以省略Me
  getClassName() {
    
    
    return Me.name;
  }
};
let inst = new MyClass();
console.log(inst.getClassName()) // Me
Me.name // 报错,Me没有定义

A class is equivalent to the prototype of an instance, and all methods defined in the class will be inherited by the instance. If you add the static keyword before a method, it means that the method will not be inherited by the instance, but will be called directly through the class, which is called a "static method".
If the static method contains the this keyword, this this refers to the class, not the instance. A static method can have the same name as a non-static method, and a static method of a parent class can be inherited by a subclass:

class Foo {
    
    
  static bar () {
    
    
    this.baz(); //等同于调用Foo.baz
  }
  static baz () {
    
    
    console.log('hello');
  }
  baz () {
    
    
    console.log('world');
  }
}
Foo.bar() // hello
 
class Bar extends Foo {
    
    
}
Bar.bar() // hello

4、import

Although import is a statement command, it is used in conjunction with the export command. The export command is used to specify the external interface of the module, and the import command is used to import the functions provided by other modules.

A module is a single file. All variables inside the file cannot be obtained from the outside. If the outside can read a variable, function or class inside the module, it must be exported using the export keyword. The variable output by export is the original name, but can be renamed using the as keyword:

// profile.js
export var firstName = 'Michael';
export function f() {
    
    };
export var year = 1958;
 
//写法2,与上等同
var firstName = 'Michael';
function f() {
    
    };
var y = 1958;
export {
    
    firstName, f, y as year};

The interface output by the export statement has a dynamic binding relationship with its corresponding value, that is, through this interface, the real-time value inside the module can be obtained. This is completely different from the CommonJS specification, where CommonJS modules output a cache of values. The export command can appear anywhere in the module, as long as it is at the top level of the module. If it is in block-level scope, an error will be reported:

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500); // 输出变量foo,值为bar,500毫秒之后变成baz
 
function foo() {
    
    
  export default 'bar' // 语法错误
}

After using the export command to define the external interface of the module, other JS files can load this module through the import command, and the variable name must be the same as the name of the external interface of the imported module (profile.js). The import command can use the as keyword to rename the input variable. In addition to specifying to load a certain output value, you can also use overall loading, that is, use * to specify an object, and all output values ​​​​are loaded on this object.

import {
    
    firstName as name, f, year} from './profile.js';
import * as p from './profile.js'; 
 
function setName(element) {
    
    
    element.textContent = name + ' ' + year; // 值等同于p.firstName + ' ' + p.year;
}

The variables input by the import command are all read-only, because its essence is an input interface. In other words, it is not allowed to rewrite the interface in the script that loads the module. However, if it is an object, rewriting the properties of the object is allowed. And because import is executed statically, expressions and variables cannot be used. These grammatical structures can only get results at runtime.

import {
    
    a} from './xxx.js'; // 也可以是绝对路径,.js后缀可以省略
 
a.foo = 'hello'; // 合法操作
a = {
    
    }; // 报错:a是只读的
 
import {
    
     'f' + 'oo' } from '/my_module.js';// 报错,语法错误(不能用运算符)
 
if (x === 1) {
    
     
  import {
    
     foo } from 'module1'; // 报错,语法错误(import不能在{}内)
} else {
    
    
  import {
    
     foo } from 'module2';
}

Note that the import command has a lifting effect, which will be lifted to the head of the entire module and executed first. import can not import anything in the module, only run the global code in the module. If the import statement of the same module is executed multiple times, its global code will only be executed once, but the variables will be imported normally (equivalent to merge processing).

foo();
import {
    
     foo } from '/my_module.js'; // 不会报错,因为import的执行早于foo的调用
import '/modules/my-module.js'; // 不引入变量,但执行其中全局代码
import {
    
     a } from '/modules/my-module.js'; // 重复引入不执行全局代码,但引入变量a

In addition to introducing variables with curly braces, import can also directly customize the introduction of default variables:

// export-default.js
export default function () {
    
    
  console.log('foo');
}
 
// import-default.js
import customName from './export-default.js'; //customName可以是任意名字
customName(); // 'foo'

insert image description here

Guess you like

Origin blog.csdn.net/weixin_71170351/article/details/127538117