CommonJs ESM
CommonJS
关键
- 社区标准而非官方标准
- 核心是用 require 函数实现
- 仅 node 环境支持
- 动态依赖,需要代码执行到 require 函数才能确定依赖,并且是同步引入执行的
原理(简单理解)
子模块中就相当于一个函数空间
在 require()后,子模块中有 this arguments
并且子模块函数空间 this 指向 module.exports exports 与 module.exports 一致
所以 this === exports === module.exports
javascript
console.log(this, exports, module.exports);
console.log(this === exports); // true {}
console.log(this === module.exports); // true {}
console.log(exports === module.exports); // true {}
exports.name = "zhangsan";
exports.age = 18;
module.exports.name = "lisi";
module.exports.age = 20;
module.exports.sex = "男";
module.exports = {
name: "zhangsan",
age: 18,
sex: "男",
};ES Module
关键
- 官方标准 所有环境都支持
- 使用新语法实现
- 同时支持静态依赖 动态依赖
- 静态依赖是代码运行前就确定的
- 动态依赖是异步的
javascript
import("./a.js");- 符号绑定(违背习惯的实现, 参考)
javascript
import { count, addCountFn } from "./count.js";
console.log(count); // 0
addCountFn();
console.log(count); // 1javascript
export let count = 0;
export function addCountFn() {
count++;
}面试
CMJ ESM 区别
CMJ 与 ESM 标准不同 CMJ 是社区标准 ESM 官方标准
CMJ 是同步动态导入 ESM 有静态 有动态 动态是异步的
运行环境不同 CMJ 通常运行在 Node
ESM 存在一个符号绑定的问题 CMJ 没
export export default 区别
export default 默认导出,可以重新用变量接收,并且一个文件只能有一个默认导出
export 具名导出, 导出的必须是已经定义好的,导出的模块对象中,命名即为模块对象的属性名,具名导出可以有多个
下边模块结果
javascript
exports.a = "a";
module.exports.b = "b";
this.c = "c";
module.exports = {
d: "d",
};分析以下题目
核心点:在****时存在符号绑定,解构 重新用变量赋值都会开辟新的内存空间
javascript
import { count, addCountFn } from "./count.js";
console.log(count); // 0
addCountFn();
console.log(count); // 1 可以看到 count 变量的值已经被改变了 由此可以看出引入时的count变量并不是一个副本,而是一个引用 指向同一个内存地址
// =======================
import { count as count2, addCountFn as addCountFn2 } from "./count.js";
console.log(count2); // 0
addCountFn2();
console.log(count2); // 1
// ========================
import * as countObj from "./count.js";
console.log(countObj.count); // 0
countObj.addCountFn();
console.log(countObj.count); // 1
// ======================
import * as countObj from "./count.js";
const { count, addCountFn } = countObj; // 解构
console.log(count); // 0
addCountFn();
console.log(count); // 0
// =========================
import { count, addCountFn } from "./count.js";
let count2 = count; // 这里是值拷贝,count2 是 count 的副本,不会影响 count 的值
console.log(count2); // 0
addCountFn();
console.log(count2); // 0javascript
import { count, addCountFn, logCountFn } from "./count.js";
count.value++; // 0 // { value: 1 }
console.log(count); // { value: 1 } // count 是一个对象,引用类型的变量可以修改其属性值
addCountFn(); // 1
console.log(count); // { value: 2 } // count 的值被修改了
logCountFn(); // 2由此可见,count 指向的确是 count.js 中的内存地址, 当 count 是一个引用对象时,对其属性的修改都会反映在两个模块 js 文件,是简单类型时,会报错 Uncaught TypeError: Assignment to constant variable.
