CommonJs
運(yùn)行時加載(動態(tài)加載)焦蘑,相當(dāng)于module.exports的那一刻進(jìn)行了值拷貝巍扛,其實(shí)就是是給 module.exports 賦予了一個新的對象,拷貝的對象里每個key和每個value和module.exports對應(yīng)
因?yàn)槭莿討B(tài)語法,所以可以寫在判斷里
獲取module.exports值的改變
第一種方式
我們知道m(xù)odule.exports實(shí)際上是執(zhí)行了值拷貝,并且新對象的key和value與module.exports對應(yīng)玻佩,那么對于引用類型的value而言,他們指向的都是同一個堆地址漱牵,當(dāng)然可以動態(tài)獲取
//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(兩個對象仍然指向同一個堆地址),結(jié)果自然會改變
第二種方式
利用函數(shù)動態(tài)獲取
//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模塊時會緩存其執(zhí)行結(jié)果酣胀,當(dāng)后面再require模塊時不會重復(fù)執(zhí)行模塊代碼,而是讀取緩存并直接拷貝當(dāng)前該模塊已經(jīng)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
//執(zhí)行b模塊時娶聘,b 中想引入 a 模塊的時候闻镶,因?yàn)?node 之前已經(jīng)加載過 a 模塊了,所以它不會再去重復(fù)執(zhí)行 a 模塊丸升,而是直接拷貝一份{a: 1}铆农,所以A.a = 1
//1
//執(zhí)行到a的打印時,b中的module.exports.b= 2修改了之前的導(dǎo)出狡耻,所以B.b = 2
//2
因?yàn)榫彺鏅C(jī)制墩剖,出現(xiàn)循環(huán)依賴時才不會出現(xiàn)無限循環(huán)調(diào)用的情況
ES6
編譯時加載,也就是靜態(tài)加載夷狰,相當(dāng)于建立了動態(tài)綁定關(guān)系岭皂,當(dāng)使用某個值時通過綁定關(guān)系,可以取到模塊內(nèi)部實(shí)時的值
import是靜態(tài)執(zhí)行沼头,所以不能使用表達(dá)式和變量爷绘,這些只有在運(yùn)行時才能得到結(jié)果的語法結(jié)構(gòu)
import和export
import在執(zhí)行時會優(yōu)先執(zhí)行,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");
}
//執(zhí)行結(jié)果
// { a: undefined, A: undefined, AA: [Function: AA] } AA是函數(shù)申明进倍,會被提取到頂部土至,所以不是undefined,而函數(shù)表達(dá)式會和變量聲明一樣猾昆,只提升A陶因,賦值操作要等到代碼執(zhí)行到具體位置,所以為undefined
多次import同一個模塊
ES6 不會再去執(zhí)行重復(fù)加載的模塊垂蜗,又由于 ES6 動態(tài)輸出綁定的特性楷扬,能保證 ES6 在任何時候都能獲取其它模塊當(dāng)前的最新值。
// 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;
//執(zhí)行結(jié)果
// undefined
// 1
// 2