1、什么是模塊化
- 到底什么是模塊化呢?
- 事實上模塊化開發(fā)最終的目的是將程序劃分成一個個小結(jié)構(gòu)
- 這個結(jié)構(gòu)編寫屬于自己的邏輯代碼程帕,有自己的作用域,不會影響別人的結(jié)構(gòu)地啰;
- 該結(jié)構(gòu)可以將自己希望暴露的變量愁拭,函數(shù)對象等導(dǎo)出給其他結(jié)構(gòu)使用。
- 也可以通過某種方式亏吝,導(dǎo)入另外結(jié)構(gòu)中的變量岭埠、函數(shù)、對象等蔚鸥;
- 上面說提到的結(jié)構(gòu)惜论,就模塊;按照這種結(jié)構(gòu)劃分開發(fā)程序的過程止喷,就是模塊化開發(fā)的過程
- 無論你多么喜歡JavaScript馆类,以及它現(xiàn)在發(fā)展的有多好,我們都需要承認(rèn)在 Brendan Eich 用了10天寫出JavaScript的時候弹谁,
它都有很多的缺陷:- 比如var定義的變量作用域問題乾巧;
- 比如JavaScript的面向?qū)ο蟛⒉荒芟癯R?guī)面向?qū)ο笳Z言一樣使用class句喜;
- 比如JavaScript沒有模塊化的問題;
2沟于、沒有模塊化帶來很多的問題
-
早期沒有模塊化帶來了很多的問題:比如命名沖突的問題
- 命名沖突
-
當(dāng)然咳胃,我們有辦法可以解決上面的問題:立即函數(shù)調(diào)用表達(dá)式(IIFE)
// 立即執(zhí)行函數(shù) (function() { })();
-
但是,我們其實帶來了新的問題:
- 第一社裆,我必須記得每一個模塊中返回對象的命名拙绊,才能在其他模塊使用過程中正確的使用;
- 第二泳秀,代碼寫起來混亂不堪标沪,每個文件中的代碼都需要包裹在一個匿名函數(shù)中來編寫;
- 第三嗜傅,在沒有合適的規(guī)范情況下金句,每個人、每個公司都可能會任意命名吕嘀、甚至出現(xiàn)模塊名稱相同的情況违寞;
-
所以,我們會發(fā)現(xiàn)偶房,雖然實現(xiàn)了模塊化趁曼,但是我們的實現(xiàn)過于簡單,并且是沒有規(guī)范的棕洋。
- 我們需要制定一定的規(guī)范來約束每個人都按照這個規(guī)范去編寫模塊化的代碼挡闰;
- 這個規(guī)范中應(yīng)該包括核心功能:模塊本身可以導(dǎo)出暴露的屬性,模塊又可以導(dǎo)入自己需要的屬性掰盘;
- JavaScript社區(qū)為了解決上面的問題摄悯,涌現(xiàn)出一系列好用的規(guī)范,接下來我們就學(xué)習(xí)具有代表性的一些規(guī)范愧捕。
3奢驯、CommonJS和Node
- 我們需要知道CommonJS是一個規(guī)范,最初提出來是在瀏覽器以外的地方使用次绘,并且當(dāng)時被命名為ServerJS瘪阁,后來為了
體現(xiàn)它的廣泛性,修改為CommonJS邮偎,平時我們也會簡稱為CJS管跺。- Node是CommonJS在服務(wù)器端一個具有代表性的實現(xiàn);
- Browserify是CommonJS在瀏覽器中的一種實現(xiàn)钢猛;
- webpack打包工具具備對CommonJS的支持和轉(zhuǎn)換伙菜;
- 所以,Node中對CommonJS進(jìn)行了支持和實現(xiàn)命迈,讓我們在開發(fā)node的過程中可以方便的進(jìn)行模塊化開發(fā):
- 在Node中每一個js文件都是一個單獨的模塊贩绕;
- 這個模塊中包括CommonJS規(guī)范的核心變量:<font color=red>exports火的、module.exports、require</font>淑倾;
- 我們可以使用這些變量來方便的進(jìn)行模塊化開發(fā)馏鹤;
- 前面我們提到過模塊化的核心是導(dǎo)出和導(dǎo)入,Node中對其進(jìn)行了實現(xiàn):
- exports和module.exports可以負(fù)責(zé)對模塊中的內(nèi)容進(jìn)行導(dǎo)出娇哆;
- require函數(shù)可以幫助我們導(dǎo)入其他模塊(自定義模塊湃累、系統(tǒng)模塊、第三方庫模塊)中的內(nèi)容碍讨;
4治力、案例設(shè)定
-
我們來看一下兩個文件:
兩個文件之間互相引用
5、exports導(dǎo)出
-
注意:exports是一個對象勃黍,我們可以在這個對象中添加很多個屬性宵统,添加的屬性會導(dǎo)出;
- exports導(dǎo)出一個對象覆获,導(dǎo)出的內(nèi)容均為exports的屬性
-
另外一個文件中可以導(dǎo)入:
- 引入
-
上面這行完成了什么操作呢马澈?理解下面這句話,Node中的模塊化一目了然
- 意味著main中的bar變量等于exports對象弄息;
- 也就是require通過各種查找方式痊班,最終找到了exports這個對象;
- 并且將這個exports對象賦值給了bar變量摹量;
- bar變量就是exports對象了涤伐;
5.1 理解對象的引用賦值
- 對象引用賦值
5.2 畫圖解析賦值的過程
- 對象引用指向共同的堆棧
5.3 它們實際上是一個淺層拷貝
- 為了進(jìn)一步論證,bar和exports是同一個對象:
- 所以荆永,bar對象是exports對象的淺拷貝(引用賦值)废亭;
-
淺拷貝的本質(zhì)就是一種引用的賦值而已国章;
淺層拷貝
6具钥、module.exports又是什么?
- 但是Node中我們經(jīng)常導(dǎo)出東西的時候液兽,又是通過module.exports導(dǎo)出的:
- <font color=red>module.exports和exports有什么關(guān)系或者區(qū)別呢骂删?</font>
- 我們追根溯源,通過維基百科中對CommonJS規(guī)范的解析:
- CommonJS中是沒有module.exports的概念的四啰;
- 但是為了實現(xiàn)模塊的導(dǎo)出宁玫,Node中使用的是Module的類,每一個模塊都是Module的一個實例柑晒,也就是
module欧瘪; - 所以在Node中真正用于導(dǎo)出的其實根本不是exports,而是module.exports匙赞;
- 因為<font color=red>module才是導(dǎo)出的真正實現(xiàn)者</font>佛掖;
- 但是妖碉,為什么exports也可以導(dǎo)出呢?
- 這是因為module對象的exports屬性是exports對象的一個引用芥被;
- 在node源碼內(nèi)部做了一個處理欧宜,
module.exports = exports
; - 也就是說 module.exports = exports = main中的bar拴魄;
6.1 畫圖解析賦值的過程
- 對象引用
- module.exports賦值成對象冗茸,重新開辟一塊空間