16.5 更多关于引入和导出的知识

16.5.1 引入代码的风格

ECMAScript 6 几种引入的代码风格:

  • 默认引入:
import localName from 'src/my_lib';
  • 命名空间方式引入:将模块作为一个对象引入(每一个属性指代一个命名导出)。
import * as my_lib from 'src/my_lib';
  • 命名引入
import { name1, name2 } from 'src/my_lib';

可以对命名引入进行重命名:

// Renaming: import `name1` as `localName1`
import { name1 as localName1, name2 } from 'src/my_lib';
  • 空引入:仅加载模块,并不引入任何内容。在程序中第一次这种引入会执行模块内的代码。
import 'src/my_lib';

仅有两种方法组合使用上述风格,并且它们出现的顺序是固定的;默认导出总是放在第一个位置。

  • 组合默认引入和命名空间引入:
import theDefault, * as my_lib from 'src/my_lib';

组合默认引入和命名引入:

import theDefault, { name1, name2 } from 'src/my_lib';

16.5.2 导出风格:内联和子句

两种方式可以导出当前模块中的东西。一种是,可以用 export 关键字标记声明。

export var myVar1 = ···;
export let myVar2 = ···;
export const MY_CONST = ···;

export function myFunc() {
    ···
}
export function* myGeneratorFunc() {
    ···
}
export class MyClass {
    ···
}

默认导出的“操作数”是一个表达式(包括函数表达式和类表达式)。例如:

export default 123;
export default function (x) {
    return x
}
export default x => x;
export default class {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

另一种,可以在模块结束处列出所有想导出的东西。

const MY_CONST = ···;
function myFunc() {
    ···
}

export { MY_CONST, myFunc };

也可以用不同的名字导出:

export { MY_CONST as FOO, myFunc };

16.5.3 重导出( re-exporting )

重导出指的是把另一个模块的导出添加到当前模块的导出中去。可以添加其它模块所有的导出:

export * from 'src/other_module';

export * 会忽略默认导出。

也可以选择性地导出(同时可以重命名):

export { foo, bar } from 'src/other_module';

// Renaming: export other_module’s foo as myFoo
export { foo as myFoo, bar } from 'src/other_module';

16.5.3.1 使重导出成为默认导出

下面的语句是另一个模块 foo 的默认导出成为当前模块的默认导出:

export { default } from 'foo';

下面的语句使模块 foo 的命名导出 myFunc 成为当前模块的默认导出:

export { myFunc as default } from 'foo';

16.5.4 所有导出风格

ECMAScript 6 提供了几种导出风格:

  • 重导出:

    • 重导出所有东西(除了默认导出):

      export * from 'src/other_module';
      
    • 通过子句重导出:

      export { foo as myFoo, bar } from 'src/other_module';
      
  • 通过子句重导出

export { MY_CONST as FOO, myFunc };
  • 内联导出:

    • 变量声明:

      export var foo;
      export let foo;
      export const foo;
      
    • 函数声明:

      export function myFunc() {}
      export function* myGenFunc() {}
      
    • 类声明:

      export class MyClass() {}
      
  • 默认导出:

    • 函数声明(可以是匿名的,但仅限于此处):

      export default function myFunc() {}
      export default function () {}
      
      export default function* myGenFunc() {}
      export default function* () {}
      
    • 类声明(可以使匿名的,但仅限于此处):

      export default class MyClass() {}
      export default class () {}
      
    • 表达式:导出值,而不是绑定。注意结束的分号。

      export default foo;
      export default 'Hello world!';
      export default 3 * 7;
      export default (function () {});
      

16.5.5 在一个模块中同时包含命名导出和默认导出

下面的场景在 JavaScript 中出人意料地常见:一个库只是一个单一的函数,但是附加的功能通过此函数的属性来提供。例如 jQuery 和 Underscore.js 。下面是 Underscore 作为一个 CommonJS 模块的粗略描绘:

//------ underscore.js ------
var _ = function (obj) {
    ···
};
var each = _.each = _.forEach =
    function (obj, iterator, context) {
        ···
    };
module.exports = _;

//------ main.js ------
var _ = require('underscore');
var each = _.each;

有了 ES6 ,函数 _ 就是默认导出, eachforEach 是命名导出。事实证明,可以同时使用命名导出和默认导出。在下例中,前面的 CommonJS 模块,被重写为 ES6 模块,看起来像这样:

//------ underscore.js ------
export default function (obj) {
    ···
}
export function each(obj, iterator, context) {
    ···
}
export { each as forEach };

//------ main.js ------
import _, { each } from 'underscore';
···

注意, CommonJS 的版本和 ECMAScript 6 的版本大致相似。后者有一个平整的解构,前者是内嵌的。

对于 ES6 模块,我通常推荐在一个单一的模块中,要么仅有默认导出,要么仅有命名导出。也就是说,不应该混合这两种导出风格。

16.5.5.1 默认导出只是另一种命名导出而已

默认导出实际上只是拥有特殊名字 default 的命名导出。也就是说,下面两个语句是等价的:

import { default as foo } from 'lib';
import foo from 'lib';

类似地,下面的两个模块有相同的默认导出:

//------ module1.js ------
export default function foo() {} // function declaration!

//------ module2.js ------
function foo() {}
export { foo as default };

16.5.5.2 default :可以作为导出名,但是不能作为变量名

不能使用保留字(比如 defaultnew )作为变量名,但是可以用于导出的名字(在 ECMAScript 5 中也可以用作属性名)。如果想直接引入这样的命名导出,就必须将其重命名为正确的变量名。

这意味着 default 只能在重命名引入的左侧出现:

import { default as foo } from 'some_module';

只能在重命名导出的右侧出现:

export { foo as default };

在重导出中, as 左右两侧都是导出名:

// The following two statements are equivalent:
export { default } from 'foo';
export { default as default } from 'foo';

export { myFunc as default } from 'foo';
export { default as otherFunc } from 'foo';

results matching ""

    No results matching ""