CommonJs和ES6 module的区别

216 阅读3分钟

记录一篇。先说结论,对于前端必须清楚。然后说明。

结论

  1. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  2. CommonJS 模块输出的是一个值的拷贝,ES6 module输出的是值的引用。
  3. CommonJS 模块的require()是同步加载模块,ES6 module的import命令是异步加载,有一个独立的模块依赖的解析阶段。
  4. import不支持动态加载,不能在if等判断语句中使用。ES2020提案 引入export ()函数export ()函数,支持动态加载模块。export ()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。export ()函数与所加载的模块没有静态连接关系,这点与export 语句不相同。export ()更类似于 Node 的require方法(CommonJS的具体实现),区别主要是。Node 的require方法是同步加载,export ()函数异步加载。

CommonJS 模块

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

上面代码的实质是整体加载fs模块(即加载的fs所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。 CommonJS 模块输出的是值的缓存,不存在动态更新,

ES6 模块

  • ES6 模块是编译时加载.能做“静态优化”。export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
  • export 命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(export 命令叫做“连接” binding 其实更合适)。不能在if等判断语句中使用。
  • export命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。
import {a} from './xxx.js'
a = {}; // Syntax Error : 'a' is read-only

export命令具有提升效果,会提升到整个模块的头部,首先执行。

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。可以用任意名称指向export-default.js输出的方法,这时就不需要知道原模块输出的函数名。需要注意的是,这时export 命令后面,不使用大括号。

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

export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量。

// 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';

// 正确
export var a = 1;

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

ps: umd

一种兼容 cjs 与 amd 的模块,既可以在 node/webpack 环境中被 require 引用,也可以在浏览器中直接用 CDN 被 script.src 引入

(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    // AMD
    define(["jquery"], factory);
  } else if (typeof exports === "object") {
    // CommonJS
    module.exports = factory(require("jquery"));
  } else {
    // 全局变量
    root.returnExports = factory(root.jQuery);
  }
})(this, function ($) {
  // ...
});

更多内容参看阮一峰老师的es6入门 es6.ruanyifeng.com/#docs/modul…