NodeJs 第五章 模块化

JavaScript 模块化机制

  • AMD (Asynchronous Module Definition): 在浏览器中使用,并用 define 函数定义模块;
  • CJS (CommonJS): 在 NodeJS 中使用,用 require 和 module.exports 引入和导出模块;
  • ESM (ES Modules): JavaScript 从 ES6(ES2015) 开始支持的原生模块机制,使用 import 和 export 引入和导出模块;

Node 对 ES Modules 支持

Node version 8.5.0 起开始支持 ES Modules 特性, 控制台需要 --experimental-modules 标记

Node version 13.2.0 起开始正式支持 ES Modules 特性, 不需要 --experimental-modules 标记,但是会有警告

Node version v14.0.0 删除警告

Node version 14.17.0 开始稳定支持 ES Modules 特性

如何在在 NodeJS 中使用 ES Modules

  • 方式一: 在 package.json 中,增加 “type”: “module” 配置;

├── index.js
└── package.json

import fs from 'fs'
console.log(fs)
  • 方式二:在 .mjs 文件可以直接使用 importexport
// index.mjs
import fs from 'fs'
console.log(fs)
  • 注意
    1. 如果 package.json 文件没有将 "type: “module” ,或者 "type: “commonjs”,会使用 CommonJS 加载模块
    2. 如果使用 .cjs, 也会使用 CommonJS 加载模块

ES Modules 和 CommonJS 区别

ES Modules

在 ESM 中,import 语句用于在解析代码时导入模块依赖的静态链接。文件的依赖关系在编译阶段就确定了。对于 ESM,模块的加载大致分为三步:
1. Construction (解析)
2. Instantiation (实例化、建立链接)
3. Evaluation (执行)

CommonJS

Node 将每个文件都视为独立的模块,它定义了一个 Module 构造函数,代表模块自身:

function Module(id = '', parent) {
  Home | This.ID = id;
  this.path = path.dirname(id);
  this.exports = {};
  this.parent = parent;
  this.filename = null;
  this.loaded = false;
  this.children = [];
};

require 函数接收一个代表模块ID或者路径的值作为参数,它返回的是用module.exports导出的对象。在执行代码模块之前,NodeJs 将使用一个包装器对模块中的代码其进行封装:

(function(exports, require, module, __filename, __dirname) { 
    // Module code actually lives in here 
});

通过这样做,Node.js 实现了以下几点:

  1. 它保持了顶层的变量(用 var、 const 或 let定义)作用在模块范围内,而不是全局对象;
  2. 它有助于提供一些看似全局的但实际上是模块特定的变量
  3. 实现者可以用于从模块中导出值的module 和 exports 对象;
  4. 包含模块绝对文件名和目录路径的快捷变量 __filename 和 __dirname ;

在包装器执行之前,模块内的导出内容是不确定的。除此之外,第一次加载的模块会被缓存到 Module._cache中

生命周期

  1. Resolution (解析)
  2. Loading (加载)
  3. Wrapping (私有化)
  4. Evaluation (执行)
  5. Caching (缓存)

你可能感兴趣的:(node,javascript,开发语言,ecmascript,node)