ES6模塊(Module)加載知識(shí)總結(jié)(二)

前言

承接上一篇《ES6模塊(Module)加載知識(shí)總結(jié)(一)》的兩個(gè)問題,
1、 由于index.js導(dǎo)入了所有的組件,然后其他頁(yè)面使用時(shí)直接加載index.js,如果我只用到其中的一兩個(gè)組件,那index.js中的其他組件會(huì)不會(huì)都加載了,如果真的加載了豈不是造成內(nèi)存的浪費(fèi)?
2、 RN中有require、exports、module.exports,還有import、export,這些都是一樣的東西嗎?
這里解答一下:

ES6中的模塊加載機(jī)制

歷史上,JavaScript 一直沒有模塊(module)體系,無法將一個(gè)大程序拆分成互相依賴的小文件,再用簡(jiǎn)單的方法拼裝起來。在 ES6 之前,社區(qū)制定了一些模塊加載方案,最主要有 CommonJS 和 AMD 兩種。之后ES6 在語(yǔ)言標(biāo)準(zhǔn)的層面上,實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單,完全可以取代 CommonJS 和 AMD 規(guī)范。下面通過對(duì)比CommonJS和ES6的模塊功能來理解ES6模塊加載。

首先,CommonJS 模塊就是對(duì)象,通過module.exports命令導(dǎo)出對(duì)象,通過require命令導(dǎo)入對(duì)象,輸入時(shí)必須查找對(duì)象屬性。

// CommonJS模塊
// index.js
moudle.exports = { NavBar, AlertBox, ChooseBox };

// Home.js
var { NavBar, AlertBox, ChooseBox } = require('../../../components/index');

// 等同于
var index = require('../../../components/index');
var NavBar = index.NavBar;
var AlertBox = index.AlertBox;
var ChooseBox = index.ChooseBox;

上面代碼的實(shí)質(zhì)是整體加載index模塊,生成一個(gè)對(duì)象index,然后再?gòu)倪@個(gè)對(duì)象上面讀取3個(gè)屬性。這種加載稱為“運(yùn)行時(shí)加載”,因?yàn)橹挥羞\(yùn)行時(shí)才能得到這個(gè)對(duì)象。運(yùn)行時(shí),當(dāng)遇到require命令,就會(huì)全部執(zhí)行,輸出已執(zhí)行部分,未執(zhí)行部分不輸出(這也是CommonJS解決循環(huán)加載的辦法)。由于require導(dǎo)入的是輸出值得拷貝。也就是說,一旦輸出一個(gè)值,模塊內(nèi)部的變化就影響不到這個(gè)值,反過來亦然。

而ES6 模塊的運(yùn)行機(jī)制與 CommonJS 不一樣。ES6 模塊的設(shè)計(jì)思想,是盡量的靜態(tài)化,使得編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。通過export命令導(dǎo)出,import命令導(dǎo)入。JS 引擎對(duì)腳本靜態(tài)分析的時(shí)候,遇到模塊加載命令import,就會(huì)生成一個(gè)只讀引用。等到腳本真正執(zhí)行時(shí),再根據(jù)這個(gè)只讀引用,到被加載的那個(gè)模塊里面去取值。換句話說,ES6 的import有點(diǎn)像 Unix 系統(tǒng)的“符號(hào)連接”,原始值變了,import加載的值也會(huì)跟著變。因此,ES6 模塊是動(dòng)態(tài)引用,并且不會(huì)緩存值。這樣宏(macro)和類型檢驗(yàn)(type system)這些只能靠靜態(tài)分析實(shí)現(xiàn)的功能就有機(jī)會(huì)在JS里實(shí)現(xiàn)了。但是由于import是靜態(tài)執(zhí)行,所以不能使用表達(dá)式、變量、if結(jié)構(gòu),這些只有在運(yùn)行時(shí)才能得到結(jié)果的語(yǔ)法結(jié)構(gòu),也就無法直接實(shí)現(xiàn)條件加載,按需加載等功能。

總結(jié)起來就是:

CommonJS 模塊是運(yùn)行時(shí)加載,ES6 模塊是編譯時(shí)輸出接口。
CommonJS 模塊輸出的是值的拷貝,ES6 模塊輸出的是值的引用。

所以問題1在ES6模塊下得到解決。

require、exports、module.exports還有import、export的區(qū)別

首先看一下他們的使用范圍:

require: node 和 es6 都支持的引入
module.exports / exports: 只有 node 支持的導(dǎo)出
export / import : 只有es6 支持的導(dǎo)出引入

在node模塊里是遵循CommonJS規(guī)范的,執(zhí)行模塊文件時(shí),會(huì)同時(shí)生成一個(gè)module對(duì)象和一個(gè)exports對(duì)象,而module對(duì)象又有一個(gè)exports屬性,他們初始化時(shí)指向同一塊{}內(nèi)存區(qū)域,注意是同一塊。即exports對(duì)象是module.exports的引用。看個(gè)例子理解一下:

// test.js
var module.exports = {};
var exports = module.exports;
console.log(module.exports);         // {}
console.log(exports);                // {}

exports.name = 2;
console.log(module.exports);         // {name: 2}
console.log(exports);                // {name: 2}

var exports = {name: 3};
console.log(module.exports);         // {name: 2}
console.log(exports);                // {name: 3}

所以從上面可以看出

其實(shí)require導(dǎo)出的內(nèi)容是module.exports指向的內(nèi)存塊內(nèi)容,并不是exports的。
區(qū)分他們之間的區(qū)別就是exports只是module.exports的引用,輔助后者添加內(nèi)容用的。
當(dāng)其中一個(gè)指向另一塊內(nèi)存時(shí),兩者便沒什么關(guān)系了。

而ES6里的模塊就非常清晰了,export導(dǎo)出引用,import導(dǎo)入引用。具體用法請(qǐng)參考大神的文章《Moudle的語(yǔ)法》

參考文章

1、《Module 的加載實(shí)現(xiàn)》
2、《exports、module.exports和export、export default到底是咋回事》

如果覺得文章對(duì)你有用,記得點(diǎn)贊喔,親!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容