CommonJs
运行时加载(动态加载),相当于module.exports的那一刻进行了值拷贝,其实就是是给 module.exports 赋予了一个新的对象,拷贝的对象里每个key和每个value和module.exports对应
因为是动态语法,所以可以写在判断里
获取module.exports值的改变
第一种方式
我们知道module.exports实际上是执行了值拷贝,并且新对象的key和value与module.exports对应,那么对于引用类型的value而言,他们指向的都是同一个堆地址,当然可以动态获取
//b.js
const obj = {
b: 1,
};
module.exports = {
obj
};
setTimeout(() => {
obj.b = 2;
});
//a.js
const {
obj,
} = require("./b.js");
console.log(obj.b);
setTimeout(() => {
console.log(obj.b);
}, 1000);
//node a.js
//1
//2
翻译一下
//b.js
let obj = {
b: 1
};
const myModule = {
exports: {}
}
myModule.exports = {
obj
}
setTimeout(() => {
obj.b = 2;
});
//a.js
const { obj: copyObj } = myModule.exports;
console.log(copyObj.b); //1
setTimeout(() => {
console.log(copyObj.b); //2
}, 1000);
//const b = require('./b');
//obj对象直接赋值给了新对象copyObj,两个对象指向同一个堆地址
//这时候改变obj.b(两个对象仍然指向同一个堆地址),结果自然会改变
第二种方式
利用函数动态获取
//b.js
let b = 1
module.exports = {
getB: () => b
};
setTimeout(() => {
b = 2;
}, 500);
//a.js
const {
getB
} = require("./b.js");
console.log(getB());
setTimeout(() => {
console.log(getB());
}, 1000);
//node a.js
//1
//2
多次require同一个模块
第一次require模块时会缓存其执行结果,当后面再require模块时不会重复执行模块代码,而是读取缓存并直接拷贝当前该模块已经module.exports的值
//b.js
module.exports.b = 1;
const A = require('./a');
console.log(A.a);
module.exports.b = 2;
//a.js
module.exports.a = 1;
const B = require('./b');
console.log(B.b);
module.exports.a = 2;
//node a.js
//执行b模块时,b 中想引入 a 模块的时候,因为 node 之前已经加载过 a 模块了,所以它不会再去重复执行 a 模块,而是直接拷贝一份{a: 1},所以A.a = 1
//1
//执行到a的打印时,b中的module.exports.b= 2修改了之前的导出,所以B.b = 2
//2
因为缓存机制,出现循环依赖时才不会出现无限循环调用的情况
ES6
编译时加载,也就是静态加载,相当于建立了动态绑定关系,当使用某个值时通过绑定关系,可以取到模块内部实时的值
import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构
import和export
import在执行时会优先执行,export会“变量提升”
// b.js
export const b = 1;
import * as a from "./a";
console.log(a);
// a.js
import { b } from "./b";
console.log("a.js");
export const a = 1;
export const A = () => {
console.log("A");
};
export function AA() {
console.log("AA");
}
//执行结果
// { a: undefined, A: undefined, AA: [Function: AA] } AA是函数申明,会被提取到顶部,所以不是undefined,而函数表达式会和变量声明一样,只提升A,赋值操作要等到代码执行到具体位置,所以为undefined
多次import同一个模块
ES6 不会再去执行重复加载的模块,又由于 ES6 动态输出绑定的特性,能保证 ES6 在任何时候都能获取其它模块当前的最新值。
// b.js
import { a } from './a';
export const b = '1';
console.log(a);
setTimeout(() => {
console.log(a);
})
// a.js
import { b } from './b';
console.log(b);
export const a = 2;
//执行结果
// undefined
// 1
// 2
网友评论