彻底搞懂ES6 Module 模块

86 阅读4分钟

image.png

历史

  • Javascript 一直没有模块体系,无法将一个大程序拆分成互相依赖的小文件。

  • ES6 之前,社区指定了一些模块加载方案,主要有 CommonJS(用于服务器) 和 AMD(用于浏览器) 。

  • ES6 :实现了Module(模块功能),完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";

运行时加载 和 编译时加载(静态加载)

运行时加载:CommonJS 。 CommonJS 模块就是对象,需要加载所需模块整体后,运行时生成一个对象,才能从对象上读取所需的方法

// CommonJS模块
let { stat, exists, readfile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;

编译时加载/静态加载:ES6 Module。 Module 模块不是对象,可以在编译时就完成模块加载,并且只加载模块上所需的方法,其他方法不加载。

// ES6模块
import { stat, exists, readFile } from 'fs';

ES6 模块功能主要由 export 和 import 两个命令构成。

  • export 规定模块对外暴露的接口
  • import 输入其他模块提供的接口
  • 一个模块就是一个独立的文件,没有使用 export 关键字输出的变量,外部无法获取

export 命令

输出变量

// a.js
export var name = 'lili';

// 等价于
var name = 'lili';
var info = { age: 18 };
export { name, info }   // 推荐使用大括号输出一组变量放在脚本尾部

// 使用 as 关键字重命名,可以实现同一个变量重复输出两次
export { name as lastName, name as firstName }

输出函数或类(class)

export function sayHello() { ... }

import 命令

  • 使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块;
  • import命令接受一对大括号,大括号里面的变量名,必须与被导入模块(a.js)对外接口的名称相同;
  • import命令输入的变量都是只读,可以视为一个常量,对其重新赋值会报错,但如果该变量是一个对象,是允许修改对象的属性,修改后其他模块也可以读取到改后的值。(不建议修改,难查错)
  • import命令具有提升效果,会自动提升到整个模块的头部,首先执行

输入

// b.js
import { name, info } from './a.js'

// 使用 as 关键字重命名
import { name as username } from './a.js'

修改

name = 'tom'  // Syntax Error : 'username' is read-only;
info.age = 20  // 合法操作

只执行,不输入任何值

import 'lodash'

整体加载 *

// * 表示整体加载, as 后紧跟着重命名
import * as VueRouter from 'vue-router'

export default 命令

从前面的例子可以看出,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

  • 这时import后面不需要大括号
  • 一个模块只能有一个默认输出,export default 命令只能用一次
  • export default 后无论是否是匿名函数,import加载时都视同匿名函数,允许你为它取任意名字
  • export default 其实只是输出一个叫做 default 的变量,所以它后面不能跟变量的声明语句

指定默认输出

// a.js
export default function() { ... }
// 等价于
export default function say() { ... }
// 等价于
function say () {...}
export default say;

// x 错误写法
export default const say = function() {}

为默认输出(匿名函数)指定任意名字后输入,

// b.js
import sayHello from './a.js';
sayHello();

ES2020 引入 import() 函数,支持动态加载模块

  • import() 是异步加载,返回一个Promise 对象
import('./myModule.js')
.then(res => {
  // ...·
});

浏览器加载 ES6 模块

  • 需要加入 type = "module"属性;
  • 浏览器对于带有type="module"的 <script>,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>标签的defer属性。
<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>

♥ ♥ ♥

如果本文给你带来了一丢丢帮助,麻烦动动手指头帮我点个赞收藏加关注,或者评论区给我留留言 ღ( ´・ᴗ・` )ღ

♥ ♥ ♥