【JavaScript】ESModule(esm)

ESModule

  • ESModule (esm) 是 ES6 的模块化方案,使用 import & export 进行导入导出
  • Node浏览器均支持 esm
    • 在 .html 文件中应用模块化,需要给 script 标签设置 type="module"
    • Node 默认支持 cjs 模块化规范。若想 Node 支持 esm,需要:
      ① 确保 Node 版本 >= 14.15.1
      ② 在 package.json 的根节点中配置 "type": "module"
  • 导入时 [路径]、[后缀] 都要写全!!!

默认导入导出

  • 一个模块只能有一个默认导出:export default XXX
  • 导入时接收的变量可自定义,符合标识符命名规范即可

demo1:

/* esm1.js */
let name = "superman";
export default name;
/* esm2.js */
import esm1 from "./esm1.js";
console.log("esm1", esm1); // esm1 superman

demo2:

/* esm1.js */
let name = "superman";
function showName() {
    console.log("name", name);
}
export default { name, showName };
/* esm2.js */
import esm1 from "./esm1.js";
console.log("esm1", esm1); // esm1 { name: 'superman', showName: [Function: showName] }

按需导入导出

  • 一个模块可以有多个导出
  • 导入时接收的变量需要与导出的标识符一样
  • 导入时可以使用 as 重命名
  • [按需导入导出] 可与 [默认导入导出] 一起使用
/* esm1.js */
export let name = "superman";
export function showName() {
    console.log("name", name);
}
export default { age: 21 }; // 默认导出
/* esm2.js */
import esm1, { name as myName, showName } from "./esm1.js";
console.log("esm1", esm1); // esm1 { age: 21 }
console.log("myName", myName); // myName superman
console.log("showName", showName); // showName [Function: showName]
  • 导入时可用 * 接收被导入文件的所有导出,需要配合 as 取别名使用:
/* esm2.js */
import * as esm1 from "./esm1.js";
console.log("esm1", esm1);
esm1 [Module: null prototype] {
    default: 21,
    name: 'superman',
    showName: [Function: showName]
}

直接执行模块

  • 导入文件时,会先执行被导入的文件,然后获取该文件导出的数据
  • 如果只想执行指定文件,而无需获取该文件导出的数据,可直接使用 import "./XXX.js"
/* esm1.js */
console.log("esm1");
/* esm2.js */
import "./esm1.js";



esm 模块化特点

① 每个模块都有自己作用域
<script>
    let name = "superman"
</script>
<script>
    console.log(name); // superman
</script>
<script type="module">
    let name = "superman"
</script>
<script type="module">
    console.log(name); // 输出空值
</script>
② 模块会被延迟解析

默认情况下,HTML 文件是从上往下解析的。如果把 script 标签放在 body 标签的前面,则无法获取 DOM 元素

<body>
    <div>superman</div>
</body>
<script>
    console.log(document.querySelector("div"));
</script>

但是,如果我们给 script 标签添加属性 type="module",则会等页面加载完成后,才执行 script 标签里面的语句

<script type="module">
    console.log(document.querySelector("div"));
</script>
<body>
    <div>superman</div>
</body>
③ 使用 esm 会将 JS 的运行模式变成 [严格模式](默认情况下,不是 [严格模式])
<script type="module">
    a = 10; // 会报错;严格模式下,变量必须被定义
</script>
④ 动态绑定
  • 使用 export 按需导出的是数据的引用,就是说 [源数据] 更新后,导入的数据也会更新
/* esm1.js */
export let age = 18;
setTimeout(() => (age = 21), 1000); // 一秒后改变 age 值
/* esm2.js */
import { age } from "./esm1.js";
console.log(age); // 18
setTimeout(() => {
    // 两秒后重新获取 age 值
    console.log(age); // 21
}, 2000);
  • 但是使用 export default 默认导出的数据不会动态绑定
/* esm1.js */
let age = 18;
export default age;
setTimeout(() => (age = 21), 1000); // 一秒后改变 age 值
/* esm2.js */
import age from "./esm1.js";
console.log(age); // 18
setTimeout(() => {
    // 两秒后重新获取 age 值
    console.log(age); // 18
}, 2000);



import 注意事项

① 即使重复写 import 语句,都只会导入一次
/* esm1.js */
console.log("esm1");
/* esm2.js */
import "./esm1.js";
import "./esm1.js";
import "./esm1.js";

看见,"esm1" 只输出了一次

import 语句提升
  • import 语句有提升效果,会提升到整个模块的最前面,首先执行

    这是因为 import 语句是编译阶段执行的,在代码运行之前

  • 因此,导入为静态加载,即不管用不用,都会先导入

foo();
import { foo } from 'my_module';
import 语句中不能使用 [表达式] / [变量]
  • 由于 import静态执行,所以不能使用 [表达式] / [变量] 这些只有在运行时才能得到结果的语法结构
// 报错
import { 'f' + 'oo' } from 'my_module'; // 不能使用 [表达式] 接收导入数据

// 报错
let module = 'my_module';
import { foo } from module; // 不能使用 [变量] 作为被导入文件的路径

// 报错:不能在语句内进行导入
if (true)
    import { foo } from 'module1';



动态导入import()

  • 因为是静态引入,所以默认的 import 语法不能写在 if 之类的语句里
  • 如果有这样的需求,我们可以使用 import() 动态导入:
if (true)
    import('./1.js');
  • 注意:动态引入,不会有 import 提升 (毕竟都不再是编译阶段执行了,变成运行时执行了)

  • import() 动态引入,返回一个 Promise 对象

    then() 的参数是导入的模块对象

import('./index2.js').then(res => {
    console.log(res); // Module {Symbol(Symbol.toStringTag): "Module"}
});



模块化 demo

思路:[ 数据 ]、[ 方法 ]、[ 逻辑处理 ] 分开放置

/* demo.js */
let a = 20;
let b = 30;
export { a, b };
/* demo2.js */
import { a, b } from "./demo.js";
const sum = () => a + b
export default sum;
<script type="module">
    import sum from '../js/demo2.js'
    console.log(sum()); // 50
</script>



CommonJs(cjs)



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JS.Huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值