js 模块化系统

444 阅读3分钟

CommonJS 模块

CommonJS 主要用于服务器端 JavaScript 程序,使用 require 语句来声明对其他模块的依赖,同时使用 exports 语句来导出当前模块内的声明。一般应用于 Node.js 程序中

  • 浏览器环境中的 JavaScript 引擎不支持 CommonJS 模块
  • CommonJS 规范,一个文件为一个模块,每个模块都为单独作用域,除非定义为 global 对象属性,否则无法被其他模块读取
  • module.exports 导出,require 方法加载模块
//utils.js
exports.add = function(x, y) {
  return x + y;
};

//index.js
var utils = require("./utils");
var total = utils.add(1, 2);
console.log(total);

AMD 模块系统

AMD,异步模块定义;使用特殊的 define 函数来注册一个模块,在一个文件中允许同时定义多个模块;AMD 模块系统中也提供了 require 函数用来声明对其他模块的依赖,同时还提供了 exports 语句用来导出当前模块内的声明。

如果想要使⽤ AMD 规范,我们还需要添加⼀个符合 AMD 规范的加载器脚本在⻚⾯中,符合 AMD 规范实 现的库很多,⽐较有名的就是 require.js。

  • 适用于浏览器环境
  • 采用异步的方式加载模块,模块的加载不影响它后面语句的运行
  • 需要使用库函数 RequireJS,解决多个 js 文件的依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  • define()定义模块,require()加载模块。
  • 推崇依赖前置,提前执行,会在最前面声明且初始化用到的所有模块
//utils
define(["require", "exports"], function(require, exports, beta) {
  exports.add = function(x, y) {
    return x + y;
  };
});

//index.js
require(["./utils.js"], function(utils) {
  console.log(utils);
  // var total = utils.add(1, 2);
  // console.log(total);
});

//index.html
<!DOCTYPE html>
<html lang="en">
  <head>
  </head>
  <body>
    <div id="app"></div>
    <!-- 加载 require.js 之类的 AMD 模块化库之后才可以继续加载模块 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
    <script src="./index.js"></script>
  </body>
</html>

CMD 模块系统

CMD,异步模块定义,类似于 AMD,定义方式和模块加载实际有区别

  • 一个文件为一个模块
  • 推崇就近依赖,只有在用到某个模块的时候再去 require
  • 需要使用库函数 SeaJS

UMD 模块系统

通用模块定义,可在浏览器中使用,也可在 Node.js 中使用;UMD 模块是基于 AMD 模块的定义,并且针对 CommonJS 模块定义进行了适配,写法适配了各种模块,较为复杂

(function(factory) {
  if (typeof module == "object" && typeof module.exports == "object") {
    var v = factory(require, exports);
    if (v !== undefined) module.exports = v;
  } else if (typeof define === "function" && define.amd) {
    define(["require", "exports"], factory);
  }
})(function(require, exports) {
  function add(x, y) {
    return x + y;
  }
  exports.add = add;
});

ESM 模块

ES6 在语言标准的层面上,实现了模块功能;模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。

模块导入/导出

  • 命名导出,每个模块包含任意数量

  • 一个模块中,可以同时存在多个命名模块导出 ( export )

//导出单个特性
export const variable1 = 1
export function FunctionName() {}
//导出列表
export { variable1, variable2 };  //命名导出列表

//解构重命名导出
export const { variable1, variable2 } = obj;

//重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };

//导出模块中除默认模块的所有模块
export * from "utils"

//导出模块中的默认模块
export { default } from "utils";


//引入方式
import { variable1, variable2 } from './utils'

//重命名导入
import { variable1 as name1, variable2 as name2 } from './utils'

//引入全部,并命变量名接收
import * as AllModule from './utils'

默认模块导出

//导入
export default function add(x, y) {
  return x + y;
};

//引入方式 可任意命名
import mkAdd from "utils"

模块混合导出

//utils
export const { variable1, variable2 } = obj;
export default function add(x, y) {
  return x + y;
};
//导入
export { default,variable1,variable2 } from "utils"; //default为默认模块
//重命名导入
import { default as module,variable1 as name1, variable2 as name2 } from './utils'