ES6 的模块加载(import)和 CommonJS(require)有两大区别:

  1. CommonJS 输出值的拷贝,ES6 输出值得引用

ES6 模块输出的是引用,类似 Unix 的 “符号链接”,import 的值不会缓存,每次都会去模块读值,也因此不能重新赋值。

  1. CommonJS 是运行时加载,ES6 是编译时加载

CommonJS 加载的是对象,只有在运行时才会生成;而 ES6 接受的是静态的定义,编译时就可以完成。

ES6 的模块是在编译时被加载的,缺点是无法实现条件加载,但优点是静态分析速度快。CommonJS 是运行时加载,可以做到条件加载,所以比较适用于后端也就是 Node 的开发环境。

比如 ES6 的 import,下面的写法不会报错:

foo();

import { foo } from 'my_module';

因为 import 是在编译时(静态)执行的,在代码运行之前。也因此,不能用表达式和变量来执行 import,比如:

if (x === 1){
  import { foo } from 'my_module1';
} else {
  import { foo } from 'my_module2';
}

以上代码会报语法错误。

====

ES6 的模块加载用的是 import 方法,而 node 用的是 CommonJS 规范的 require

Node 采用 CommonJS 规范加载模块,因为 Node 的主要应用场景在后端(服务器),所有文件都保存在本地,而 CommonJS 又是运行时(同步)加载,所以读取快,这样做比较合理。但是在前端(浏览器),更合理的方式是采用 ES6 的编译时(异步)加载。

===

此外,CommonJS 在加载时(require)会执行整个脚本,然后输出一个对象,之后再遇到 require 就直接返回第一次的结果而不会执行,除非手动清理系统缓存。

ES6 在用 import 加载模块时也会执行,多次 import 只会执行一次

ES6 的 import

导出指定变量的时候如下:

--- a.js ---
export var a = 1


--- b.js ---
import { a } from '.a'

若不指定变量:(本质上是把后面的值赋给 default 变量,所以 export default var a = 1 是不合法的)

--- a.js ---
export default 1

--- b.js ---
import a from '.a'

用 export default 的时候,import 可以不用加 {},名字也可以自定义。default 也可以和其它具名变量一起导入:

--- a.js ---
export default function (obj) {
  // ···
}

export function each(obj, iterator, context) {
  // ···
}

export { each as forEach };

--- b.js ---
import _, { each, forEach } from 'a';

也可以把模块当做入口,直接导出另一个模块:

export { foo, bar } from 'my_module';

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

// 整体导出,注意 * 会忽略 default 方法
export * from 'my_module';

// 导出默认
export { default } from 'foo';

// 具名接口改默认
export { es6 as default } from './someModule';

// 默认接口改具名
export { default as es6 } from './someModule';

当用 import 加载 CommonJS 时,module.export 会被当做 export default 默认输出