ECMAScript 6 的模块相比 CommonJS 的require (...)有什么优点?

感觉语法比 CommonJS 繁琐多了es6.ruanyifeng.com/#
关注者
356
被浏览
25831
ECMAScript 6 很多新功能都是毁誉参半,其中添加的一个新功能「模块 Module」也一样,有人认为 Module 可以帮助我们更好地写代码,也有人认为这增加了 Javascript 的复杂度,大多数人其实并不需要它。
到底是好是坏,这里不去辩别。但目前 Module 的语法已经定下来了,我们可以来探索下它。

ECMAScript 6 的模块有什么优点?

三个字:爽,快,强。

爽?
1. 语言层级支持,无需引入第三方库
2. 统一的 API,不用再写 [shim](umdjs/umd · GitHub)
3. 清爽的语法(与 Python 相似),功能却很丰富:
import:
import * as _ from 'src/lodash';           // 引入外部文件所有对象
import { each, map } from 'src/lodash';    // 引入外部文件部分对象
import _ from 'src/lodash';                // 引入外部文件默认导出对象
import _, { each, map } from 'src/lodash'; // 同时引入默认导出对象和部分对象
import 'src/lodash';                       // 只加载外部文件,但啥都不引入

export:
export let _ = function () {};           // 导出 _ 对象
export function lodash () {};            // 导出 lodash 函数
export default function (x) {return x};  // 导出匿名函数并设为默认导出对象
export { _, lodash as default };         // 一次导出多个对象

4. 由于可以选择性引入并重命名外部模块的部分对象,因此全局变量不被污染,局部变量也不怕被污染。

快?
1. 静态代码分析
基于目前第三方依赖管理工具的实现,我们要通过运行时检查当前模块引入了哪些外部模块,效率较低。但现在有了新语法的支持,我们就可以在运行前判断得出模块之间的依赖关系,进行代码检查。
2. 上一条已经很劲爆了有木有 :)

强?
1. 更好地支持循环依赖
循环依赖示例:
/* --- a.js --- */
import * as b from 'js/b';

// 在模块中间调用其它模块的方法
b.bar('b');

export function foo (from) {
  console.log('caller: ' + from);
}

/* --- b.js --- */
import * as a from 'js/a';

// 在模块中间调用其它模块的方法
a.foo('a');

export function bar (from) {
  a.foo(from);
}

/* --- main.js --- */
import {bar} from 'js/b';
bar('main');

结果:
caller: b         a.js:7
caller: a         a.js:7
caller: main      a.js:7

2. 提供模块加载器接口(Module Loader API)
有了这个接口后,模块的加载就有了更多的可能性,比如动态加载,加载后回调等。但我对于这个接口熟知不多,详见介绍: The ECMAScript 6 module loader API

延伸阅读:
  1. harmony:modules [ES Wiki]
  2. ECMAScript 6 modules: the final syntax