Written in the beginning

  • ES6 common but ignored methods series of articles, sorting out the author thinks that some daily development may use some methods, use skills and some application scenarios, details please see related content links, welcome to supplement exchange.

Related articles

  • Common but overlooked methods for ES6 (Destruct assignments and values first)
  • ES6 Common but ignored methods (second bullet functions, arrays, and objects)
  • ES6 common but ignored methods (third bullet Symbol, Set, and Map)
  • ES6 commonly used but overlooked methods (fourth bullet Proxy and Reflect)
  • ES6 common but ignored methods (# 5 Promise and Iterator)
  • Common but ignored methods for ES6 (Generator 6)
  • ES6 Common but ignored methods (async)
  • ES6 Common but ignored methods (eighth bullet Class)
  • Common but ignored methods of ES6 (Development specification of the Tenth Bullet Project)
  • ES6 common but ignored method (eleventh bullet Decorator)
  • Common but overlooked approaches to ES6 (End game – Latest Proposal)

Module

  • ES6-Module
  • CommonJSAMDModules can only determine these things at run time.ES6Modules can be loaded at compile time, which is much more efficientCommonJSModules are loaded in a high way, called “compile-time loading” or static loading.
  • advantage
    1. Can further broadenJavaScriptSyntax, such as introducing macros (macro) and type checking (type system) functions that can only be implemented by static analysis.
    2. No longer needUMDModule format.
    3. A new browser for the futureAPIIt can be provided in module format and no longer has to be a global variable ornavigatorObject properties.
    4. Objects are no longer required as namespaces (e.gMathObject), and in the future these functions could be provided through modules.

Strict mode

  • ES6The module automatically adopts strict mode, whether you add it to the module header or not"use strict".
  • Limitations:
    1. Variables must be declared before being used
    2. Function arguments cannot have attributes of the same name; otherwise, an error is reported
    3. You can’t usewithstatements
    4. Cannot assign a value to a read-only attribute, otherwise an error is reported
    5. Can’t use prefixes0Represents an octal number, otherwise an error is reported
    6. You cannot delete attributes that cannot be deleted; otherwise, an error is reported
    7. Cannot delete variablesdelete prop, an error is reported, and only attributes can be deleteddelete global[prop]
    8. evalNo variables are introduced in its outer scope
    9. evalandargumentsCannot be reassigned
    10. argumentsDoes not automatically reflect changes in function parameters
    11. You can’t usearguments.calleeandarguments.caller
    12. banthisPointing to a global object
    13. You can’t usefn.callerandfn.argumentsGets the stack of function calls
    14. Added reserved words (e.gprotected,staticandinterface)
  • Note in particular the limitation of this.ES6In modules, at the top levelthisPoint to theundefinedThat is, should not be used in top-level codethis.

The export command

  • exportCommand is used to specify the external interface of a module.
  • A module is an independent file. All variables inside the file are not available externally. You must use this function if you want outsiders to be able to read a variable inside the moduleexportKeyword output the variable. In addition to output variables, you can also output functions or classes (class).
// index.js export const name = 'detanx'; export const year = 1995; export function multiply(x, y) { return x * y; }; // const name = 'detanx'; const year = 1995; function multiply(x, y) { return x * y; }; export { name, year, multiply }Copy the code
  • exportThe output variable is the original name, but can be usedasThe keyword is renamed. After the rename, you can print it multiple times with different names.
function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};
Copy the code
  • exportCommands specify external interfaces and must establish a one-to-one correspondence with variables inside the module.
Export 1; var m = 1; export m; Export var m = 1; var m = 1; export {m}; var n = 1; export {n as m};Copy the code
  • exportCommands can appear anywhere in the module, as long as they are at the top of the module.
  • export *Commands ignore modulesdefaultMethods.
// export * from 'my_module';Copy the code

The import command

  • useexportCommand defines the external interface of the module, and otherJSThe file can go throughimportCommand to load the module. To give the input variable a new name,importCommand to useasKeyword to rename the input variable.
import { name, year } from './index.js';
import { name as username } from './profile.js';
Copy the code
  • The variables entered by the import command are read-only because it is by nature an input interface. That is, it is not allowed to rewrite interfaces in scripts that load modules. If a is an object, overwriting a’s properties is allowed.
import {a} from './xxx.js' a = {}; // Syntax Error : 'a' is read-only; a.foo = 'hello'; // It is validCopy the code
  • importAt the back of thefromSpecifies the location of the module file, which can be relative or absolute..jsThe suffix can be omitted. If it is just the module name with no path, then there must be a configuration file (e.gwebpackConfigure the path), tellsJavaScriptEngine position of the module.
import {myMethod} from 'util';
Copy the code
  • importCommands are promoted to the head of the module and executed first.
foo(); Import {foo} from 'my_module';Copy the code
  • importIt executes statically, so you can’t use expressions and variables, which are syntactic structures that only get results at run time.
Import {'f' + 'oo'} from 'my_module'; // let module = 'my_module'; import { foo } from module; If (x === 1) {import {foo} from 'module1'; } else { import { foo } from 'module2'; }Copy the code
  • Repeat the same sentence many timesimportStatement, then it is executed once, not multiple times.
import 'lodash'; import 'lodash'; Import {foo} from 'my_module'; import { bar } from 'my_module'; // Equivalent to import {foo, bar} from 'my_module';Copy the code

Overall loading of modules

  • Instead of specifying an output value to load, you can also use the whole load, using the asterisk (*) specifies an object to which all output values are loaded.
import * as user from './index.js'; user.name; // 'detanx' user.year; / / 1995Copy the code

Export the default command

  • export defaultCommand to specify default output for the module. When other modules load this module,importCommand (importYou can specify any name for this anonymous function.
// export-default.js
export default function () {
  console.log('detanx');
}

// import-default.js
import customName from './export-default';
customName(); // 'detanx'
Copy the code
  • useexport default, corresponding toimportStatements do not need braces; useexport, the correspondingimportThe statement requires braces.A module can only have one default output, soexport defaultThe command can be used only once.
export default function crc32() { ... } import crc32 from 'crc32'; export function crc32() { ... }; import { crc32 } from 'crc32';Copy the code

A compound of export and import

  • If you input and then output the same module in a module, importStatements can be associated withexportStatements written together.So when I write a line,fooandbarIt is not actually imported into the current module, but merely forwards the two interfaces so that the current module cannot be used directlyfooandbar.
export { foo, bar } from 'my_module'; Import {foo, bar} from 'my_module'; export { foo, bar };Copy the code
  • The interface name and overall output of a module can also be written in this way.
Export {foo as myFoo} from 'my_module'; // export * from 'my_module';Copy the code
  • The default interface is written as follows.
export { default } from 'foo';
Copy the code
  • The named interface is changed to the default interface as follows.
export { es6 as default } from './someModule'; // Import {es6} from './someModule'; export default es6;Copy the code
  • Similarly, the default interface can be renamed to a named interface.
export { default as es6 } from './someModule'; Before ES2020, there was an import statement with no corresponding compound. import * as someIdentifier from "someModule";Copy the code
  • ES2020I’ve made up this notation.
export * as ns from "mod"; Import * as ns from "mod"; export {ns};Copy the code

application

  1. Public module
    • For example, a project has many public methods put into oneconstantWe load whatever we need.
    // Constants. Js module export const A = 1; export const B = 3; export const C = 4; // use.js import {A, B} from './constants';Copy the code
  2. import()
    • importCommand will beJavaScriptEngine static analysis, executed before other statements in the module (importThe command is called “Connect”bindingMore appropriate). So we can only use it at the top level.ES2020The introduction ofimport()Function to support dynamic loading of modules.
    • import()Returns aPromiseObject.
    const main = document.querySelector('main');
    
    import(`./section-modules/${someVariable}.js`)
      .then(module => {
        module.loadPageInto(main);
      })
      .catch(err => {
        main.textContent = err.message;
      });
    Copy the code
    • import()Functions can be used anywhere, not just in modules, but also in non-module scripts. It is run time execution, that is, whenever this sentence is run, the specified module is loaded. In addition,import()Unlike import statements, functions are not statically linked to loaded modules.import()Similar to theNoderequireMethod, the main difference is that the former is asynchronous loading, the latter is synchronous loading.
    • Application Scenario Modules are loaded on demand, conditionally loaded, and dynamically.
  3. Pay attention to the point
    • import()Once the module is successfully loaded, the module is treated as an objectthenMethod parameters. Therefore, you can use the syntax of object deconstruction assignment to get the output interface.
    import('./myModule.js') .then(({export1, export2}) => { // ... });Copy the code
    • In the code above,export1andexport2Are allmyModule.jsThe output interface can be deconstructed.
    • If the module hasdefaultOutput interface, can be obtained directly with parameters.
    import('./myModule.js')
    .then(myModule => {
      console.log(myModule.default);
    });
    Copy the code
    • The above code could also use named input.
    import('./myModule.js')
    .then(({default: theDefault}) => {
      console.log(theDefault);
    });
    Copy the code
    • If you want to load multiple modules at the same time, you can write the following.
    Promise.all([ import('./module1.js'), import('./module2.js'), import('./module3.js'), ]) .then(([module1, module2, Module3]) => {···});Copy the code
    • import()Can also be used inasyncDelta function.
    async function main() {
      const myModule = await import('./myModule.js');
      const {export1, export2} = await import('./myModule.js');
      const [module1, module2, module3] =
        await Promise.all([
          import('./module1.js'),
          import('./module2.js'),
          import('./module3.js'),
        ]);
    }
    main();
    Copy the code

Module loading implementation

  • Es6-module load implementation

Introduction to the

  1. Traditional load
    • By default, browsers load synchronouslyJavaScriptThe script that the rendering engine encounters<script>The tag will stop, wait until the script is finished, and then continue rendering down. In order to solve the<script>TABdeferorasyncProperty, the script will load asynchronously.
    • deferwithasyncThe difference between:deferWait until the entire page is properly rendered in memory (DOMStructure is fully generated, and other scripts are executed).asyncOnce the download is complete, the rendering engine interrupts the rendering, executes the script, and continues rendering. In a word,deferIt’s “render before you execute”,asyncIt’s “Execute as you download”. In addition, if there are multipledeferScripts are loaded in the order they appear on the page, and multipleasyncScripts do not guarantee the load order.
  2. Load the rules
    • Browser loadingES6Module, also used<script>Tag, but addtype="module"Properties. It’s the same thing as turning it on<script>Of the labeldeferProperties.
    <script type="module" src="./foo.js"></script> <! - equivalent to -- > < script type = "module" SRC = ". / foo. Js "defer > < / script >Copy the code
    • There are a few things to note about external module scripts.
      1. Code is run in module scope, not global scope. The top-level variable inside the module is not visible outside.
      2. Module scripts automatically adopt strict mode, declared or not"use strict".
      3. Module, can be usedimportCommand to load other modules (.jsSuffixes cannot be omitted; they need to provide the absoluteURLOr relativeURL), can also be usedexportCommand output external interface.
      4. In modules, at the top levelthisKeyword returnundefinedInstead of pointingwindow. That is, at the top of the modulethisKeywords are meaningless.
      5. If the same module is loaded more than once, it is executed only once.
      import utils from 'https://example.com/js/utils.js';
      const x = 1;
      
      console.log(x === window.x); //false
      console.log(this === undefined); // true
      Copy the code
    • Utilizing top-levelthisIs equal to theundefinedThis syntax point detects whether the current code is inES6Module.
    const isNotModuleScript = this ! == undefined;Copy the code

Differences between ES6 modules and CommonJS modules

  • discussNode.jsloadingES6Modules must be understood beforeES6Module andCommonJSModules are completely different.
  • There are two important differences.
    1. CommonJSThe module outputs a copy of the value,ES6A module outputs references to values.
    2. CommonJSModules are loaded at runtime,ES6A module is a compile-time output interface. (because theCommonJSAn object is loaded (i.emodule.exportsProperty), which is generated only after the script has run. An ES6 module is not an object, and its external interface is a static definition that is generated during the code static parsing phase.
  • CommonJSA module outputs a copy of a value, that is, once a value is output, changes within the module do not affect that value. You have to write it as a function to get the internal value.
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, }; // main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // lib. Js var counter = 3; function incCounter() { counter++; } module.exports = { get counter() { return counter }, incCounter: incCounter, }; $ node main.js 3 4Copy the code
  • ES6A module is referenced dynamically and does not cache values. Variables in a module are bound to the module in which they reside.
// lib.js export let counter = 3; export function incCounter() { counter++; } // main.js import { counter, incCounter } from './lib'; console.log(counter); // 3 incCounter(); console.log(counter); / / 4Copy the code
  • ES6The input module variable is just a “symbolic link”, so this variable is read-only and reassigning it will report an error.
// lib.js
export let obj = {};

// main.js
import { obj } from './lib';

obj.prop = 123; // OK
obj = {}; // TypeError
Copy the code
  • exportThrough the interface, the output is the same value. Different scripts load the interface and get the same instance.
// mod.js
function C() {
  this.sum = 0;
  this.add = function () {
    this.sum += 1;
  };
  this.show = function () {
    console.log(this.sum);
  };
}

export let c = new C();
Copy the code
  • The script abovemod.jsThe output is oneCThe instance. Different scripts load the module and get the same instance.
// x.js
import {c} from './mod';
c.add();

// y.js
import {c} from './mod';
c.show();

// main.js
import './x';
import './y';
Copy the code
  • Now performmain.jsAnd the output is1.
$ babel-node main.js
1
Copy the code
  • To prove thex.jsandy.jsIt’s all loadedCThe same instance of.

Node. Js loading

  • Node.jsrequirementsES6The module USES the.mjsSuffix file name.Node.jsencounter.mjsFile, just think it isES6Modules, strict mode is enabled by default and need not be specified at the top of every module file"use strict".

If you don’t want to change the suffix to.mjs, you can specify the type field as module in your project’s package.json file.

{
   "type": "module"
}
Copy the code
  • You also need to use CommonJS modules, so you need to change the CommonJS script suffix to.cjs. If there is no type field, or if the type field is CommonJS, the.js script will be interpreted as a CommonJS module.

  • Summary:.mjs files are always loaded as ES6 modules,.cjs files are always loaded as CommonJS modules, and.js files are loaded depending on the setting of the type field in package.json.

  • Pay attention to,ES6Module andCommonJSTry not to mix modules.requireCommand cannot load.mjsFile, will report an error, onlyimportThe command can be loaded.mjsFile. In turn,.mjsYou can’t use it in a filerequireCommand is mandatoryImport.

  • ES6 modules and CommonJS support each other in node.js.

Cyclic loading

  • “Cyclic loading” (circular dependency)Refers to,aScript execution dependenciesbThe script,bScript execution depends onaThe script. “Loop loading” indicates strong coupling and, if not handled well, can lead to recursive loading that makes the program unable to execute, so it should be avoided, but it can be difficult to avoid, especially on very complex projects.