[ES6] Ruan Yifeng ES6 Learning Module Grammar

1 Introduction

Before ES6, there were mainly two kinds of CommonJSand AMD. CommonJS for the server, AMD for the browser. ES6 implements module functions at the level of language standards, and the implementation is quite simple. It can completely replace CommonJS and AMD specifications and become a common module solution for browsers and servers. Entered the grand unification stage.

The design idea of ​​ES6 modules is to be as static as possible, makingcompile timeYou can determine the dependencies of the module, as well as the input and output variables. Both CommonJS and AMD modules can only be used inRuntimeMake sure of these things.

// CommonJS模块
let {
    
     stat, exists, readfile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

This kind of loading is called "runtime loading", because this object can only be obtained at runtime, resulting in no way to do "static optimization" at compile time.

exportES6 modules are not objects, but codes that explicitly specify output through commands, and then importinput through commands.

// ES6模块
import {
    
     stat, exists, readFile } from 'fs';

The essence of the above code is to load 3 methods from the fs module, and other methods are not loaded. This loading is called "compile-time loading" or static loading. That is, ES6 can complete module loading at compile time, which is more efficient than CommonJS module loading. Of course, this also makes it impossible to reference the ES6 module itself, since it's not an object.

2. Strict mode

ES6 modules automatically adopt strict mode, whether you add it to the module header or not "use strict".

Strict mode mainly has the following restrictions.

  • Variables must be declared before they can be used
  • The parameters of the function cannot have attributes with the same name, otherwise an error will be reported
  • cannot use the with statement
  • You cannot assign a value to a read-only attribute, otherwise an error will be reported
  • Undeletable attributes cannot be deleted, otherwise an error will be reported
  • Variables cannot be deleted delete prop, an error will be reported, only attributes can be deleteddelete global[prop]
  • evalDoes not introduce variables in its outer scope
  • evaland argumentscannot be reassigned
  • argumentsDoes not automatically reflect changes in function parameters
  • Out of servicearguments.callee
  • Out of servicearguments.caller
  • Do not thispoint to the global object
  • Can't use fn.callerand fn.argumentsget the stack of a function call
  • Added reserved words (such as protected, staticand interface)

3. export command

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

A module is a single file. All variables inside the file cannot be obtained from the outside. If you want the outside to be able to read a variable inside the module, you must use exportthe keyword to output the variable. Below is a JS file that uses exportcommand output variables.

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

// 另一种写法
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {
    
     firstName, lastName, year };

exportIn addition to outputting variables, commands can also output functions or classes.

export function multiply(x, y) {
    
    
  return x * y;
};

The above code outputs a function externally multiply.

Normally, exportthe output variable is the original name, but can be asrenamed using keywords.

function v1() {
    
     ... }
function v2() {
    
     ... }

export {
    
    
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

What needs special attention is that exportthe command specifies the external interface, which must establish a one-to-one correspondence with the variables inside the module.

// 报错
export 1;

// 报错
var m = 1;
export m;

The above two ways of writing will report an error, because no external interface is provided. The first way of writing is directly output 1, and the second way of writing mis output directly through variables 1. 1Just a value, not an interface. The correct way of writing is as follows.

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {
    
    m};

// 写法三
var n = 1;
export {
    
    n as m};

The above three writing methods are all correct, specifying the external interface m. Other scripts can get the value 1 through this interface. Their essence is to establish a one-to-one correspondence between the interface name and the internal variables of the module.

Similarly, the output of functionand classmust also follow this way of writing.

// 报错
function f() {
    
    }
export f;

// 正确
export function f() {
    
    };

// 正确
function f() {
    
    }
export {
    
    f};

4. import command

After using exportthe command to define the external interface of the module, other JS files can importload this module through the command.

// main.js
import {
    
     firstName, lastName, year } from './profile.js';

function setName(element) {
    
    
  element.textContent = firstName + ' ' + lastName;
}

If you want to rename the input variable, importthe command must use askeywords to rename the input variable.

import {
    
     lastName as surname } from './profile.js';

importThe variables entered by the 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.

import {
    
    a} from './xxx.js'

a = {
    
    }; // Syntax Error : 'a' is read-only;

In the above code, the script loads the variable a, and if it is reassigned, an error will be reported, because a is a read-only interface. However, if ait is an object, overriding aproperties are allowed.

import {
    
    a} from './xxx.js'

a.foo = 'hello'; // 合法操作

5. Overall loading of modules

In addition to specifying to load a certain output value, you can also use overall loading, that is, use an asterisk (*) to specify an object, and all output values ​​​​are loaded on this object.

Below is a circle.js file that exports two methods area and circumference.

// circle.js

export function area(radius) {
    
    
  return Math.PI * radius * radius;
}

export function circumference(radius) {
    
    
  return 2 * Math.PI * radius;
}

Now, load this module.

// main.js

import {
    
     area, circumference } from './circle';

console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));

The above method is to specify the methods to be loaded one by one, and the overall loading method is as follows.

import * as circle from './circle';

console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));

Note that the object where the module is loaded as a whole (circle in the above example) should be statically analyzable, so runtime changes are not allowed. The following writing is not allowed.

import * as circle from './circle';

// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {
    
    };

6. export default command

When using importthe command, the user needs to know the name of the variable or function to be loaded, otherwise it cannot be loaded. However, users definitely want to get started quickly, and may not be willing to read the documentation. So for convenience, the command is used to export defaultspecify the default output for the module.

// export-default.js
export default function () {
    
    
  console.log('foo');
}

The above code is a module file export-default.js, and its default output is a function.

When other modules load this module, importthe command can specify any name for the anonymous function.

// import-default.js
import customName from './export-default';
customName(); // 'foo'

The command of the above code importcan use any name to point to export-default.jsthe output method. At this time, there is no need to know the function name output by the original module. It should be noted that importcurly braces are not used after the command at this time.

export defaultIt is also possible to use commands before non-anonymous functions.

// export-default.js
export default function foo() {
    
    
  console.log('foo');
}

// 或者写成

function foo() {
    
    
  console.log('foo');
}

export default foo;

In the above code, foothe function name of the function foois invalid outside the module. When loading, it is regarded as an anonymous function loading.

// 第一组
export default function crc32() {
    
     // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() {
    
     // 输出
  // ...
};

import {
    
    crc32} from 'crc32'; // 输入

The above two groups of codes are written, the first group is used export default, the corresponding importstatement does not need to use braces; the second group is not used export default, the corresponding importstatement needs to use braces.

The export default command is used to specify the default output of the module. Obviously, a module can only have one default output, so the export default command can only be used once. Therefore, there is no need to use braces after the import command, because it can only correspond to the export default command.

In essence, export defaultit is to export a defaultvariable or method called , and then the system allows you to give it any name. Therefore, the following writing is valid.

// modules.js
function add(x, y) {
    
    
  return x * y;
}
export {
    
    add as default};
// 等同于
// export default add;

// app.js
import {
    
     default as foo } from 'modules';
// 等同于
// import foo from 'modules';

7. Compound writing of export and import

If in a module, the same module is input first and then output, importthe statement can exportbe written together with the statement.

export {
    
     foo, bar } from 'my_module';

// 可以简单理解为
import {
    
     foo, bar } from 'my_module';
export {
    
     foo, bar };

In the above code, the exportAND importstatement can be combined and written into one line. However, it should be noted that after being written in one line, fooand baris not actually imported into the current module, but is equivalent to forwarding these two interfaces externally, so that the current module cannot directly use fooand bar.

The interface renaming and overall output of the module can also be written in this way.

// 接口改名
export {
    
     foo as myFoo } from 'my_module';

// 整体输出
export * from 'my_module';

The default interface is written as follows.

export {
    
     default } from 'foo';

The writing method of changing the named interface to the default interface is as follows.

export {
    
     es6 as default } from './someModule';

// 等同于
import {
    
     es6 } from './someModule';
export default es6;

Likewise, the default interface can also be renamed to a named interface.

export {
    
     default as es6 } from './someModule';

Before ES2020, there was an import statement, but there was no corresponding compound writing method.

import * as someIdentifier from "someModule";

ES2020 added this way of writing.

export * as ns from "mod";

// 等同于
import * as ns from "mod";
export {
    
    ns};

Guess you like

Origin blog.csdn.net/Bon_nenul/article/details/128315440
Recommended