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

前言

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

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

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

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

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

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

總結(jié)起來就是:

CommonJS 模塊是運(yùn)行時加載,ES6 模塊是編譯時輸出接口。
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í)行模塊文件時,會同時生成一個module對象和一個exports對象,而module對象又有一個exports屬性,他們初始化時指向同一塊{}內(nèi)存區(qū)域,注意是同一塊。即exports對象是module.exports的引用??磦€例子理解一下:

// 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)其中一個指向另一塊內(nèi)存時,兩者便沒什么關(guān)系了。

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

參考文章

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容