模块:将大程序拆分成互相依赖的小文件,再用简单的方法拼接起来
commonjs:let { stat, exists, readFile } = require('fs');
- 实质是整体加载
fs
模块(即加载fs
的所有方法),生成一个对象(_fs
),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。
ES6:import { stat, exists, readFile } from 'fs';
【ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";
】
通过
export
命令显式指定输出的代码,再通过import
命令输入实质是从
fs
模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。【希望外部能够读取模块内部的某个变量,就必须使用export
关键字输出该变量,可以使用as
关键字重命名,⚠️export与对应的值动态绑定!!!而commonjs输出值得缓存,不存在动态更新】export、import不能出现 在块级作用域内,只要处于模块顶层就可以❗️
import
命令要使用as
关键字,将输入的变量重命名,输入的变量都是只读的,但是改写a
的属性是允许的由于
import
是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。import
命令具有提升效果,会提升到整个模块的头部,首先执行。⚠️使用
export default
时,对应的import
语句不需要使用大括号动态加载,
require
到底加载哪一个模块,只有运行时才知道。import
命令做不到这一点。
const path = './' + fileName;
const myModual = require(path);
-
因此引入
import()
返回一个 Promise 对象,import()
函数可以用在任何地方。它是运行时执行,什么时候运行到这一句,就会加载指定的模块。import()
类似于 Node 的require
方法,区别主要是前者是异步加载,后者是同步加载。- 按需加载:
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
- 条件加载
if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}
- 动态的模块路径
import(f())
.then(...);
model的加载实现
默认情况下,浏览器是同步加载 JavaScript 脚本,如果是外部脚本,还必须加入脚本下载的时间。(defer
是“渲染完再执行”,async
是“下载完就执行”。另外,如果有多个defer
脚本,会按照它们在页面出现的顺序加载,而多个async
脚本是不能保证加载顺序的。)
- 浏览器加载 ES6 模块,也使用
<script>
标签,但是要加入type="module"
属性。<script type="module" src="./foo.js"></script>
带有type="module"
的<script>
,都是异步加载,等同于defer
ES6模块 VS CommonJs
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令
import
,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。ES6 模块是动态引用,并且不会缓存值
// m1.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
// m2.js
import {foo} from './m1.js';
console.log(foo);
setTimeout(() => console.log(foo), 500); // bar baz
- ES6 模块之中,顶层的
this
指向undefined
;CommonJS 模块的顶层this
指向当前模块,这是两者的一个重大差异。
AMD
AMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。
用require.js实现AMD规范的模块化:用
require.config()
指定引用路径等,用define()
定义模块,用require()
加载模块。
CMD
- CMD是另一种js模块化方案,它与AMD很类似,不同点在于:AMD 推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行