推荐阅读:https://zh.javascript.info/import-export

export导出
我们可以通过在声明之前放置 export 来标记任意声明为导出,无论声明的是变量,函数还是类都可以。

例如,这里的所有导出均有效:

// 导出数组
export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

// 导出 const 声明的变量
export const MODULES_BECAME_STANDARD_YEAR = 2015;

// 导出类
export class User {
  constructor(name) {
    this.name = name;
  }
}

导出与声明分开
另外,我们还可以将 export 分开放置。

下面的例子中,我们先声明函数,然后再导出它们:

function sayHi(user) {
  alert(`Hello, ${user}!`);
}

function sayBye(user) {
  alert(`Bye, ${user}!`);
}

export {sayHi, sayBye}; // 导出变量列表

Import *
通常,我们把要导入的东西列在花括号 import {...} 中,就像这样:

import {sayHi, sayBye} from './say.js';

sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!

如果有很多要导入的内容,我们可以使用 import * as 将所有内容导入为一个对象

import * as say from './say.js';

say.sayHi('John');
say.sayBye('John');

Import “as” 和 Export “as”

我们也可以使用 as 让导入具有不同的名字。

import {sayHi as hi, sayBye as bye} from './say.js';

hi('John'); // Hello, John!
bye('John'); // Bye, John!
export {sayHi as hi, sayBye as bye};

现在 hi 和 bye 是在外面使用时的正式名称

Export default 导出的是一个模块
在实际中,主要有两种模块。

包含库或函数包的模块,像上面的 say.js
声明单个实体的模块,例如模块 user.js 仅导出 class User。
大部分情况下,开发者倾向于使用第二种方式,以便每个“东西”都存在于它自己的模块中。

当然,这需要大量文件,因为每个东西都需要自己的模块,但这根本不是问题。实际上,如果文件具有良好的命名,并且文件夹结构得当,那么代码导航(navigation)会变得更容易。

模块提供了一个特殊的默认导出 export default 语法,以使“一个模块只做一件事”的方式看起来更好。

将 export default 放在要导出的实体前:

export default class User { // 只需要添加 "default" 即可
  constructor(name) {
    this.name = name;
  }
}

每个文件应该只有一个 export default:

……然后将其导入而不需要花括号:

import User from './user.js'; // 不需要花括号 {User},只需要写成 User 即可

new User('John');

不用花括号的导入看起来很酷。刚开始使用模块时,一个常见的错误就是忘记写花括号。所以,请记住,import 命名的导出时需要花括号,而 import 默认的导出时不需要花括号。

命名导出
由于每个文件最多只能有一个默认的导出,因此导出的实体可能没有名称。

例如,下面这些都是完全有效的默认的导出:

export default class { // 没有类名
  constructor() { ... }
}
export default function(user) { // 没有函数名
  alert(`Hello, ${user}!`);
}
// 导出单个值,而不使用变量
export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

不指定名称是可以的,因为每个文件只有一个 export default,因此不带花括号的 import 知道要导入的内容是什么。

如果没有 default,这样的导出将会出错:

export class { // Error!(非默认的导出需要名称)
  constructor() {}
}

“default” 名称
在某些情况下,default 关键词被用于引用默认的导出。

例如,要将函数与其定义分开导出:

function sayHi(user) {
  alert(`Hello, ${user}!`);
}

// 就像我们在函数之前添加了 "export default" 一样
export {sayHi as default};

或者,另一种情况,假设模块 user.js 导出了一个主要的默认的导出和一些命名的导出(这种情况很少见,但确实会发生):

export default class User {
  constructor(name) {
    this.name = name;
  }
}

export function sayHi(user) {
  alert(`Hello, ${user}!`);
}

这是导入默认的导出以及命名的导出的方法:

import {default as User, sayHi} from './user.js';

new User('John');

如果我们将所有东西 * 作为一个对象导入,那么 default 属性正是默认的导出:

import * as user from './user.js';

let User = user.default; // 默认的导出
new User('John');

命名的导出会强制我们使用正确的名称进行导入:

import {User} from './user.js';
// 导入 {MyUser} 不起作用,导入名字必须为 {User}

……对于默认的导出,我们总是在导入时选择名称:

import User from './user.js'; // 有效
import MyUser from './user.js'; // 也有效
// 使用任何名称导入都没有问题

重新导出
“重新导出(Re-export)”语法 export ... from ... 允许导入内容,并立即将其导出(可能是用的是其他的名字),就像这样:

export {sayHi} from './say.js'; // 重新导出 sayHi

export {default as User} from './user.js'; // 重新导出 default

重新导出默认导出
重新导出时,默认导出需要单独处理。

假设我们有一个 user.js 脚本,其中写了 export default class User,并且我们想重新导出类 User:

export default class User {
  // ...
}

我们可能会遇到两个问题:

  • export User from './user.js' 无效。这会导致一个语法错误。

要重新导出默认导出,我们必须明确写出 export {default as User},就像上面的例子中那样。

  • export * from './user.js' 重新导出只导出了命名的导出,但是忽略了默认的导出。

如果我们想将命名的导出和默认的导出都重新导出,那么需要两条语句:

export * from './user.js'; // 重新导出命名的导出
export {default} from './user.js'; // 重新导出默认的导出

动态导入
下面这样的 import 行不通:

import ... from getModuleName(); // Error, only from "string" is allowed

if(...) {
  import ...; // Error, not allowed!
}

{
  import ...; // Error, we can't put import in any block
}

import() 表达式

let modulePath = prompt("Which module to load?");

import(modulePath)
  .then(obj => <module object>)
  .catch(err => <loading error, e.g. if no such module>)

//或者导入 say 中的两个函数
let {hi, bye} = await import('./say.js');

hi();
bye();

//或者  默认的导出
let obj = await import('./say.js');
let say = obj.default;
// or, in one line: let {default: say} = await import('./say.js');

say();

尽管 import() 看起来像一个函数调用,但它只是一种特殊语法,只是恰好使用了括号(类似于 super())。
因此,我们不能将 import 复制到一个变量中,或者对其使用 call/apply。因为它不是一个函数。

标签: none

添加新评论