ES Module 的 import 导入和 import () 动态导入介绍
一、ES Module 简介
ES Module 是 JavaScript 官方提供的标准化模块系统,它的出现解决了长期以来 JavaScript 在模块管理方面的混乱局面。通过 ES Module,开辟者可以更加方便地组织和复用代码,进步代码的可维护性和可扩展性。
二、import 导入
(一)基本语法
import 默认导出
在一个模块中,可以使用export default来定义默认导出。比方,在myModule.js文件中:
- // myModule.js
- const myFunction = () => {
- console.log("这是一个默认导出的函数");
- };
- export default myFunction;
复制代码 在另一个模块中导入这个默认导出:
- // main.js
- import myFunction from "./myModule.js";
- myFunction(); // 输出:这是一个默认导出的函数
复制代码 import 具名导出
模块中也可以使用具名导出,将多个变量、函数或类分别导出。比方:
- // mathModule.js
- export const add = (a, b) => a + b;
- export const subtract = (a, b) => a - b;
复制代码 在其他模块中导入具名导出:
- // main.js
- import { add, subtract } from "./mathModule.js";
- console.log(add(2, 3)); // 输出:5
- console.log(subtract(5, 3)); // 输出:2
复制代码 也可以给 import 的具名导出起别名:
- // main.js
- import { add as sum, subtract as difference } from "./mathModule.js";
- console.log(sum(2, 3)); // 输出:5
- console.log(difference(5, 3)); // 输出:2
复制代码 混合导入
一个模块可以同时有默认导出和具名导出,在导入时也可以混合使用:
- // myModule.js
- const myDefaultFunction = () => {
- console.log("这是默认导出的函数");
- };
- export const myVariable = 42;
- export default myDefaultFunction;
复制代码- // main.js
- import myDefaultFunction, { myVariable } from "./myModule.js";
- myDefaultFunction(); // 输出:这是默认导出的函数
- console.log(myVariable); // 输出:42
复制代码 (二)import 的特点
静态性:import语句在编译阶段就会被解析,这意味着它不能出现在运行时才执行的逻辑中,比如if语句块内。这使得 JavaScript 引擎可以在代码执行前对模块依赖进行分析和优化。
提拔:import语句会被提拔到模块的顶部,即使在代码中它出现在其他语句之后,也会先于其他语句执行。
三、import () 动态导入
(一)基本语法
import()是 ES2020 引入的动态导入语法,它返回一个Promise。这使得我们可以在运行时根据条件动态地加载模块。比方:
- // main.js
- const condition = true;
- if (condition) {
- import("./myModule.js")
- .then((module) => {
- module.default(); // 假设 myModule.js 有默认导出
- })
- .catch((error) => {
- console.error("加载模块失败", error);
- });
- }
复制代码 如果模块是具名导出,可以如许使用:
- // main.js
- import("./mathModule.js")
- .then((module) => {
- console.log(module.add(2, 3)); // 假设 mathModule.js 有具名导出 add 函数
- })
- .catch((error) => {
- console.error("加载模块失败", error);
- });
复制代码 (二)支持导入 CommonJS
在 Node.js 情况中,import()语法还支持导入 CommonJS 模块。CommonJS 是一种广泛使用的 JavaScript 模块规范,尤其是在 Node.js 应用中。当使用import()导入 CommonJS 模块时,必要注意以下几点:
转换规则
CommonJS特性ESM转换体现module.exports成为默认导出default属性exports.xxx转换为具名导出属性exports.default不会特殊处理动态导出大概无法正确识别- const cjsModule = await import('./legacy-module.cjs');
- console.log(cjsModule.default); // 默认导出
- console.log(cjsModule.namedExport); // 具名导出
复制代码 默认导出与定名导出:CommonJS 模块只有一个exports对象用于导出内容,通过import()导入时,默认导出的是整个exports对象。比方,有一个 CommonJS 模块commonModule.js:
- // commonModule.js(CommonJS模块)
- const myValue = 10;
- exports.myValue = myValue;
- exports.anotherFunction = () => {
- console.log("这是CommonJS模块中的另一个函数");
- };
复制代码 在 ES Module 中使用import()导入该模块:
- // main.js
- import("./commonModule.js")
- .then((module) => {
- console.log(module.myValue); // 输出:10
- module.anotherFunction(); // 输出:这是CommonJS模块中的另一个函数
- })
- .catch((error) => {
- console.error("加载模块失败", error);
- });
复制代码 兼容性:虽然import()支持导入 CommonJS 模块,但在不同的运行情况中,其兼容性大概有所不同。在 Node.js 中,从 Node.js 13.2.0 版本开始原生支持通过import()导入 CommonJS 模块。在浏览器情况中,情况相对复杂,一些现代浏览器大概对导入 CommonJS 模块的支持并不完善,这时候大概必要借助工具如 Babel 和 Webpack 来进行处理,将 CommonJS 模块转换为 ES Module 格式,以确保代码在各种情况中都能正常运行。
(三)import () 的优势
代码拆分:在大型应用中,通过import()可以实现代码的按需加载,将应用的代码拆分成多个小块,只有在必要的时候才加载相应的模块,从而进步应用的初始加载性能。
条件加载:可以根据运行时的条件来决定加载哪个模块,增长了代码的灵活性。比方,根据用户的语言偏好加载不同语言的翻译模块。
(四)import() 导入怎样清除缓存
在使用import()动态导入模块时,缓存机制大概会导致加载旧版本的模块内容。根据模块类型不同,清除缓存的方式也有所差异。
导入 ES Module :ES Module 的缓存机制相对严格,要确保每次都加载最新文件,可在每次调用import()时,对文件地址添加不同的查询参数,以此强制浏览器或 Node.js 重新请求该模块。比方:
- const modulePath = './myModule.js';
- const uniqueModulePath = `${modulePath}?v=${Date.now()}`;
- import(uniqueModulePath)
- .then((module) => {
- // 使用模块
- })
- .catch((error) => {
- console.error('加载模块失败', error);
- });
复制代码 上述代码通过Date.now()天生一个随时间变革的唯一值作为查询参数,确保每次请求的模块路径不同,从而避免缓存。
导入 Common JS 模块:在 Node.js 情况中,CommonJS 模块的缓存管理与 ES Module 不同。若要手动清除缓存,需借助require方法。在 ES Module 中,本身没有直接的require方法,但可通过以下方式获取:
- import { createRequire } from "module";
- const require = createRequire(import.meta.url);
复制代码 获取require方法后,就能像在 Common JS 模块中一样清除缓存。假设要动态加载并确保每次获取最新的 Common JS 模块legacyModule.cjs:
- const modulePath = './legacyModule.cjs';
- delete require.cache[require.resolve(modulePath)];
- const module = require(modulePath);
- // 也可以使用import()
- import(modulePath).then((module)=>{
- console.log(module)
- })
复制代码 这段代码先通过require.resolve(modulePath)获取模块在缓存中的路径,再从require.cache中删除该路径对应的缓存,确保下次require / import 时重新加载模块。
通用加载方案:若不确定要加载的模块是 ES Module 还是 Common JS 模块,可构建一个通用的加载函数,综合上述两种方式来处理缓存题目。以下是一个示例:
- import path from "path";import { pathToFileURL } from "url";import { createRequire } from "module";
- const require = createRequire(import.meta.url);
- function loadFile(filePath) { delete require.cache[require.resolve(filePath)]; const fileUrl = pathToFileURL(path.resolve(filePath)).href; const urlWithCacheBuster = `${fileUrl}?v=${Date.now()}`; return import(urlWithCacheBuster) .then((module) => { return module.default || module; }) .catch((err) => { console.error(`文件加载失败 ${modulePath}:`, err); });}export { loadFile };
复制代码 此函数loadFile 首先手动清除 Common JS 模块的缓存,再通过添加查询参数避免ES Module缓存;最后通过import 加载文件。如许无论模块是何种类型,都能尽大概确保加载到最新内容。
四、import 和 import () 的区别
静态与动态:import是静态导入,在编译阶段确定依赖关系;import()是动态导入,在运行时确定依赖关系。
使用场景:import适用于那些在模块初始化时就必要加载的依赖;import()更适合用于代码拆分和条件加载的场景。
语法形式:import是声明式语法,而import()是函数调用语法,返回一个Promise。
五、总结
ES Module 的import导入和import()动态导入为开辟者提供了强盛的模块管理能力。import的静态特性使得代码的依赖关系更加清晰,便于优化;import()的动态特性则为代码的灵活性和性能优化提供了更多大概。在现实开辟中,我们应根据具体的需求选择符合的导入方式,以构建高效、可维护的 JavaScript 应用。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |