在 ES6 之前,Modules 只能通过引入库来实现,而加入 Modules 算是 ES6 的一个比较大的改变。接下来看看 ES6 中的 Modules 都能做什么?
概览
ES6 的 Modules 是以文件划分的,一个文件就是一个 Module。它导出的方式分为两种,一种是导出多个变量,一种是导出默认值,这两种方式你可以一起用,但是推荐是分开的,两个小例子:
1 . 分开 export
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
或者是直接导出整个的 module
//------ main.js ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
2 . 导出默认值
带标签的形式
export default function foo() {} // no semicolon!
export default class Bar {} // no semicolon!
匿名形式
//------ myFunc.js ------
export default function () { ··· } // no semicolon!
//------ main1.js ------
import myFunc from 'myFunc';
myFunc();
导出默认值
在匿名导出的时候,如果需要导出的是表达式,并不是函数,需要加括号。
export default (function () {});
export default (class {});
另外也可以导出表达式的值:
export default 'abc';
export default foo();
export default /^xyz$/;
export default 5 * 7;
export default { no: false, yes: true };
如何处理循环引用(cyclic dependencies)
需要注意的是,不能在 Modules 中访问 imports,我的理解是只能在 export 中。 举个例子,包含执行顺序:
//------ a.js ------
import {bar} from 'b'; // (i)
export function foo() {
bar(); // (ii)
}
//------ b.js ------
import {foo} from 'a'; // (iii)
export function bar() {
if (Math.random()) {
foo(); // (iv)
}
}
Imports 几个要点
a . Imports 不管在什么位置,它都会被优先引用,所以下面的情况是合法的。
foo();
import { foo } from 'my_module';
b . Imports 在 exports 中是只读的
// 可以把 x 理解成常量
import x from 'foo'
// 可以把 foo 理解成冻结的对象 (frozen object)
import * as foo from 'foo'
c . Imports 的几种形式
1 . 默认引用 import localName from 'src/my_lib';
2 . 作为一个对象 import * as my_lib from 'src/my_lib';
3 . 按名称引用 import { name1, name2 } from 'src/my_lib';
4 . 重命名
// Renaming: import `name1` as `localName1`
import { name1 as localName1, name2 } from 'src/my_lib';
// Renaming: import the default export as `foo`
import { default as foo } from 'src/my_lib';
5 空引用,只是为了执行 module 里面的代码 import 'src/my_lib';
两种形式(默认,其它)结合引用
// 默认加命名空间(对象)
import theDefault, * as my_lib from 'src/my_lib';
// 默认加名称
import theDefault, { name1, name2 } from 'src/my_lib';
Exports 几个要点
1 . 分开 export
export var myVar1 = ···;
export let myVar2 = ···;
export const MY_CONST = ···;
export function myFunc() {
···
}
export function* myGeneratorFunc() {
···
}
export class MyClass {
···
}
2 . 在一个地方,一起 export
const MY_CONST = ···;
function myFunc() {
···
}
export { MY_CONST, myFunc };
// 另外也可以给 export 起别名,关键词是 as
export { MY_CONST as FOO, myFunc };
3 . re-export 其它 module 比如
// 不包括默认 export
export * from 'src/other_module';
// 默认 export 跟重命名
export { foo as myFoo, bar } from 'src/other_module';
export { default } from 'src/other_module';
export { default as foo } from 'src/other_module';
export { foo as default } from 'src/other_module';
总结
在 ES6 之前,主要有 CommondJS(同步) 跟 AMD(异步) 两种 module 的方式。它们之间的语法,肯定是有区别的。但是 ES6 是在他们的基础上实现的,当然做了一些改进,从语言层面的一种支持。万变不离其宗,使用方面其实是很像的。强烈推荐看一下这篇文章 链接,内容更丰富,也更有助于理解,我主要是在这个的基础上,按我想的结构调整了一下。
Resources
http://exploringjs.com/es6/ch_modules.html#sec_mixing-named-and-default-exports
https://babeljs.io/docs/learn-es2015/#modules
http://www.2ality.com/2014/09/es6-modules-final.html