认识
一、认识
ES6 Module
也被称作 ES Module
(或 ESM
), 是由 ECMAScript
官方提出的模块化规范,作为一个官方提出的规范,ES Module
经过五年多的发展,不仅得到了众多浏览器的原生支持,也在 Node.js
中得到了原生支持,是一个能够跨平台的模块规范。。在现代浏览器中,如果在 HTML
中加入含有type="module"
属性的 script
标签,那么浏览器会按照 ES Module
规范来进行依赖加载和模块解析。EsModule
通过 export
关键字导出模块中的功能,可以是变量、函数、类等。使用 import
关键字导入其他模块的功能。
Es Module
加载机制: 通过 import
语句静态分析、导入, 也就是说在编译时就完成加载。也可以通过 import()
函数进行异步、动态导入,允许按需加载模块。
Es Module
加载时机: ES Module
是静态编译, 即编译时加载, 也就是说在编译时就完成加载, 因此在编译时就能够确定模块的依赖关系, 输入和输出变量。意味着在代码执行之前, 需要对模块结构进行分析, 所以 import
语句必须位于模块最顶层。Es Module
同样支持 import()
动态导入, 异步加载模块, 返回一个 Promise
。
Es Module
缓存机制: ES Module
使用 URL
或者相对路径作为模块标识。每个模块的加载是基于其 URL
的唯一性。当一个模块通过 import
语句被加载时,浏览器(或 JavaScript
运行时环境)会解析其 URL
,并将模块内容缓存起来。这个缓存是基于模块的 URL
的。模块的缓存是通过 URL
进行标识和管理的。如果一个模块的 URL
相同,则表示它是同一个模块,浏览器会重用之前缓存的实例,而不是重新加载和执行模块代码。包括通过动态导入语法 import()
,可以异步加载模块。这种动态加载也会受到缓存机制的影响,即相同的 URL
会返回缓存中的模块实例。
Es Module
导出结果: ES Module
模块导入的实例都是单例的, 当多个模块导入同一个模块时,所有导入都引用相同的模块实例。模块的内容(例如导出的变量、函数、对象等)在整个应用中只有一个实例。修改模块的内容(如变量、对象属性等)会影响所有引用该模块的地方,因为它们引用的是同一个实例。综上所述: ES Modules
确保了导出的模块在整个应用中只有一个实例。所有对该模块的引用都共享同一个实例,确保状态的一致性。
Es Module Tree shaking
是基于 ES6
模板语法(import
与exports
),主要是借助ES6
模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量, 进而判断哪些模块已经加载, 哪些模块和变量未被使用或者引用,进而删除对应代码。
二、语法
2.1 基础语法
定义模块
// 命名导出
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 默认导出
export default function multiply(a, b) {
return a * b;
}
使用模块
// 导入命名导出
import { add, subtract } from './math';
// 导入默认导出
import multiply from './math';
console.log(add(1, 2)); // 3
console.log(subtract(5, 3)); // 2
console.log(multiply(2, 3)); // 6
// 动态导入
import('./math').then(module => {
console.log(module.add(1, 2)); // 3
});
2.2 导出结果
Es Module
导出结果: ES Module
模块导入的实例都是单例的, 当多个模块导入同一个模块时,所有导入都引用相同的模块实例。模块的内容(例如导出的变量、函数、对象等)在整个应用中只有一个实例。修改模块的内容(如变量、对象属性等)会影响所有引用该模块的地方,因为它们引用的是同一个实例。综上所述: ES Modules
确保了导出的模块在整个应用中只有一个实例。所有对该模块的引用都共享同一个实例,确保状态的一致性。
一、验证a.js
、c.js
导入 b.js
, a.js
修改 b.js
中的变量,c.js
是否有影响?:
// b.js
export let e = 1;
import { e } from './d.js';
e = 5;
console.log(e); // 输出: 5
// c.js
import { e } from './d.js';
console.log(e); // 输出: 5
-
a.js
、c.js
都导入了b.js
模块中的e
变量。 -
a.js
修改了e
的值。 -
因为
e
是b.js
中单一实例的引用,c.js
中也会反映a.js
的修改。 -
结果是
c.js
中的e
变量的值是5
。
二、验证a.js
、c.js
导入 b.js
, a.js
修改 b.js
中的对象属性值,c.js
是否有影响?:
// b.js
export let e = { value: 1 };
import { e } from './d.js';
e.value = 5;
console.log(e.value); // 输出: 5
// c.js
import { e } from './d.js';
console.log(e.value); // 输出: 5
-
a.js
、c.js
都导入了b.js
模块中的e
对象属性值。 -
a.js
修改了e
的对象属性值。 -
因为
e
是b.js
中单一实例的引用,c.js
中也会反映a.js
的修改。 -
结果是
c.js
中的e.value
变量的值是5
。