export & import | ES Module

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

为何需要 ES Module

历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。

无模块概念

一开始,将每个功能及其相关数据,各自单独放到不同的 JS 文件,作为不同的可执行脚本,然后通过 <script> 元素引用

<script src="./a.js"></script>
<script src="./b.js"></script>
复制代码

但一旦脚本增加,具有越来越多变量、函数等,不但容易产生命名冲突,而且作用于全局作用域,无法确定依赖关系,维护难度增加

模块化规范

Javascript 程序本来很小——在早期,它们大多被用来执行独立的脚本任务,在你的 web 页面需要的地方提供一定交互,所以一般不需要多大的脚本。过了几年,我们现在有了运行大量 Javascript 脚本的复杂程序

模块化可理解为:将 JavaScript 程序拆分为可按需导入的单独模块的机制

为了更好地组织脚本代码,偏向以一个 JS 文件作为入口文件,根据需要来针对性引用功能模块,发展了一些模块化标准规范:

规范 特点 简要说明
CommonJS 规范 同步加载 - 避免引起大量的同步请求,不适用于浏览器
- 通过 module.exports 导出成员,通过 require 函数载入模块
AMD 规范 异步加载 - 适用于浏览器
- 通过 define 函数定义模块,通过 require 函数自动加载模块 (加载模块时,自动创建 script 标签去请求并执行模块代码)
- 使用起来相对复杂
- 若模块划分越来越多,可能引起页面具有大量的脚本资源请求
UMD规范 规范集合 - CommonJS 规范 + AMD 规范
- 浏览器端、服务器端都适用

(PS:# JS模块化规范,浅谈一下模块化规范的差异)

ES6 模块功能

ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案

ES6 模块功能的主要特性:exportimport,一个输出另一个输入,利于确定模块依赖关系

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量

  • 静态加载,好处:可进行静态分析(不执行代码,从字面量上对代码进行分析),即利于 # Tree-shaking,在编译时消除无用代码

  • 异步加载:不会造成堵塞浏览器,页面渲染完毕,再执行脚本。具体加载原理,详见 # 传送门

export先输出

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

export 命令用于规定模块的对外接口,主要用法如下:

命名输出

此方式可输出多个变量、函数或类(class),即一个模块可以有任意个命名输出

export let num = 1;   // √
export let name = 'alison';   // √

export 2;   // X,直接输出,未提供对外的接口
复制代码

或指定输出的一组变量:

let num = 1;   
let name = 'alison';

export {num, name};   // √,使用{}指定输出的变量

export num;   // X,还是直接输出,未提供对外的接口
复制代码

支持重命名

支持使用 as 关键字重命名

let num = 1;   
let name = 'alison';

export {num as number, name};   // √,num 重命名为 number
复制代码

默认输出

一个模块中只能有一个默认导出export default, 即只能使用一次

let num = 1;   
let name = 'alison';

export default {num, name};   // √,默认输出
复制代码

import再输入

import 命令用于输入指定模块提供的功能

  • 输入的变量、函数或类 只读(对象较特殊),均不建议改写

  • from后指定模块文件的位置,可相对路径,可绝对路径,可模块名(需具有配置文件)

  • 具有提升效果,类似变量提升效果,import的执行先于对应的调用

  • 不能使用表达式和变量

主要用法

对应 export命令输出方式:

输出 输入 代码 备注
命名输出(任意个) 需{} import {num, name} from './demo.js' - 输入模块命名不可随意
- 支持重命名输入
import {num as number, name} from './demo.js'
默认输出(只有一个) 无需{} import demo from './demo.js' - 输入模块命名可随意
import MyDemo from './demo.js'也可

整体输入

*as指定一个对象,将所有输出都加载到该对象

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

console.log(demo.num);   // √
console.log(demo.name);   // √
复制代码

链接传送门

Last but not least

如有不妥,请多指教~

猜你喜欢

转载自juejin.im/post/7035172488401125389