如何使用 ES6 中的 modules
发布于 8 年前 作者 lmore 3281 次浏览 来自 分享

在 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

回到顶部