浅析 ES6 模块导出与导入语法


背景介绍

ES6 模块的导出语法虽然只有三种:默认导出、逐个导出以及批量导出,但由于其允许同时使用多种导出语法,如不注意,导入模块很有可能获取不到导出内容。

导出模块只使用一种导出语法

以下 ... // 定义导出内容 包含的就是正常的定义变/常量、函数或类,如:let val = 1function getVal() { return ... }

默认导出与导入:

... // 定义导出内容
export default 标识符; // 此处的标识符代表之前定义的某个变/常量、函数或类。(后面是猜测)默认导出的标识符对于导入模块是无意义的,导入模块始终会对其重命名,即使两个标识符相同

import 导入标识符 from 路径; // 导入标识符可以与导出时使用的标识符不同,此时即视为隐式重命名
import { default as 新标识符 } from 路径; // 对只有默认导出的模块重命名必须使用default关键字以及大括号

匿名默认导出与导入,注意一个模块只能存在一个默认导出:

... // 定义导出内容
export default { ... }; // 大括号内部可包含部分或所有之前定义的内容

// 对只有匿名默认导出的模块,必须重命名,且必须使用default关键字以及大括号
import { default as 新标识符 } from 路径; 

逐个导出与按需导入:

export 类型关键字1 标识符1 = 值1;
export 类型关键字2 标识符2 = 值2;
... // 更多导出

import { 标识符1 as 新标识符,标识符1,... } from 路径; // 此处的标识符与导出模块相同

批量导出与按需导入:

... // 定义导出内容
export { 标识符1,标识符2, ... };

import { 标识符1 as 新标识符,标识符1,... } from 路径; // 此处的标识符与导出模块相同

导出模块使用多种语法混合导出

以下例子只是作为参考,建议最好只使用一种导出语法,避免导入困难。
为了方便理解,给出实际示例:

// 逐个导出
export 类型关键字1 标识符1 = 值1; // 导入时重命名
export 类型关键字2 标识符2 = 值2;
// 批量导出
类型关键字4 标识符4 = 值4;
类型关键字5 标识符5 = 值5;
export { 标识符2, 标识符3 }
类型关键字6 标识符6 = 值6;
... // 更多定义内容
export default 标识符6;
// 默认导出为匿名值
// export default 变/常量、函数、类;


// 注意默认导出如果不需要重命名,则标识符必须位于大括号外面
import 标识符6, { 标识符1 as 新标识符,标识符2,标识符4, 标识符5, ... } from 路径; 
// 若需要重命名,则位于大括号里面,且必须使用 default 关键字
import { default as 新标识符1, 标识符1 as 新标识符2,标识符2,标识符4, 标识符5, ... } from 路径; 

实际示例

导出模块:

// 逐个导出
export const value1 = 1; // 导入后重命名为 value3
export const value2 = 2;
// 批量导出
const value4 = 4;
const value5 = 5;
export { value4, value5 };
const value6 = 6;
export default value6

导入模块:

import {
  default as value7,
  value1 as value3,
  value2,
  value4,
  value5,
} from 路径;

简单总结

  • JS 允许同时使用多种导出语法。
  • 逐个导出与批量导出的模块,在按需导入时语法相同。
  • 导出命名值时,必须将命名变/常量、函数、类等定义在导出语句之前,包括导入再导出。因此建议始终将导出语句置于模块末尾。
  • 导入时重命名的项必须被包含在大括号内,包括默认导出重命名。
  • 对默认导出重命名,必须使用 default 关键字,而不能使用导出时的标识符,即 { default as 新标识符 },而不是 { 默认导出标识符 as 新标识符}

(只是猜测,未验证官方定义或浏览器源码)默认导出使用的标识符只是用于定位需要导出的值,对于导入模块是无意义或者说不可访问的。导入模块始终会对默认导出执行重命名,即使两个标识符名字相同。可能是由于 ES6 模块语法的内部实现机制,使得默认导出只能通过 default 关键字获取其内容,导出时使用的标识符会在导出后被舍弃。