Javascript模塊化和Node模塊化

1、什么是模塊化

  • 到底什么是模塊化呢?
    • 事實(shí)上模塊化開發(fā)最終的目的是將程序劃分成一個(gè)個(gè)小結(jié)構(gòu)
    • 這個(gè)結(jié)構(gòu)編寫屬于自己的邏輯代碼,有自己的作用域,不會(huì)影響別人的結(jié)構(gòu);
    • 該結(jié)構(gòu)可以將自己希望暴露的變量,函數(shù)對(duì)象等導(dǎo)出給其他結(jié)構(gòu)使用。
    • 也可以通過某種方式,導(dǎo)入另外結(jié)構(gòu)中的變量、函數(shù)、對(duì)象等;
  • 上面說提到的結(jié)構(gòu),就模塊;按照這種結(jié)構(gòu)劃分開發(fā)程序的過程,就是模塊化開發(fā)的過程

  • 無論你多么喜歡JavaScript,以及它現(xiàn)在發(fā)展的有多好,我們都需要承認(rèn)在 Brendan Eich 用了10天寫出JavaScript的時(shí)候,
    它都有很多的缺陷:
    • 比如var定義的變量作用域問題;
    • 比如JavaScript的面向?qū)ο蟛⒉荒芟癯R?guī)面向?qū)ο笳Z言一樣使用class;
    • 比如JavaScript沒有模塊化的問題;

2、沒有模塊化帶來很多的問題

  • 早期沒有模塊化帶來了很多的問題:比如命名沖突的問題

    • 命名沖突
  • 當(dāng)然,我們有辦法可以解決上面的問題:立即函數(shù)調(diào)用表達(dá)式(IIFE)

        // 立即執(zhí)行函數(shù)  
        (function() {
            
        })();
    

  • 但是,我們其實(shí)帶來了新的問題:

    • 第一,我必須記得每一個(gè)模塊中返回對(duì)象的命名,才能在其他模塊使用過程中正確的使用;
    • 第二,代碼寫起來混亂不堪,每個(gè)文件中的代碼都需要包裹在一個(gè)匿名函數(shù)中來編寫;
    • 第三,在沒有合適的規(guī)范情況下,每個(gè)人、每個(gè)公司都可能會(huì)任意命名、甚至出現(xiàn)模塊名稱相同的情況;
  • 所以,我們會(huì)發(fā)現(xiàn),雖然實(shí)現(xiàn)了模塊化,但是我們的實(shí)現(xiàn)過于簡(jiǎn)單,并且是沒有規(guī)范的。

    • 我們需要制定一定的規(guī)范來約束每個(gè)人都按照這個(gè)規(guī)范去編寫模塊化的代碼
    • 這個(gè)規(guī)范中應(yīng)該包括核心功能:模塊本身可以導(dǎo)出暴露的屬性,模塊又可以導(dǎo)入自己需要的屬性;
    • JavaScript社區(qū)為了解決上面的問題,涌現(xiàn)出一系列好用的規(guī)范,接下來我們就學(xué)習(xí)具有代表性的一些規(guī)范。

3、CommonJS和Node

  • 我們需要知道CommonJS是一個(gè)規(guī)范,最初提出來是在瀏覽器以外的地方使用,并且當(dāng)時(shí)被命名為ServerJS,后來為了
    體現(xiàn)它的廣泛性,修改為CommonJS,平時(shí)我們也會(huì)簡(jiǎn)稱為CJS。
    • Node是CommonJS在服務(wù)器端一個(gè)具有代表性的實(shí)現(xiàn);
    • Browserify是CommonJS在瀏覽器中的一種實(shí)現(xiàn);
    • webpack打包工具具備對(duì)CommonJS的支持和轉(zhuǎn)換;
  • 所以,Node中對(duì)CommonJS進(jìn)行了支持和實(shí)現(xiàn),讓我們?cè)陂_發(fā)node的過程中可以方便的進(jìn)行模塊化開發(fā):
    • 在Node中每一個(gè)js文件都是一個(gè)單獨(dú)的模塊;
    • 這個(gè)模塊中包括CommonJS規(guī)范的核心變量:<font color=red>exports、module.exports、require</font>;
    • 我們可以使用這些變量來方便的進(jìn)行模塊化開發(fā)
  • 前面我們提到過模塊化的核心是導(dǎo)出和導(dǎo)入,Node中對(duì)其進(jìn)行了實(shí)現(xiàn):
    • exports和module.exports可以負(fù)責(zé)對(duì)模塊中的內(nèi)容進(jìn)行導(dǎo)出;
    • require函數(shù)可以幫助我們導(dǎo)入其他模塊(自定義模塊、系統(tǒng)模塊、第三方庫模塊)中的內(nèi)容;

4、案例設(shè)定

  • 我們來看一下兩個(gè)文件:


    兩個(gè)文件之間互相引用

5、exports導(dǎo)出

  • 注意:exports是一個(gè)對(duì)象,我們可以在這個(gè)對(duì)象中添加很多個(gè)屬性,添加的屬性會(huì)導(dǎo)出;

    • exports導(dǎo)出一個(gè)對(duì)象,導(dǎo)出的內(nèi)容均為exports的屬性
  • 另外一個(gè)文件中可以導(dǎo)入:

    • 引入

  • 上面這行完成了什么操作呢?理解下面這句話,Node中的模塊化一目了然

    • 意味著main中的bar變量等于exports對(duì)象;
    • 也就是require通過各種查找方式,最終找到了exports這個(gè)對(duì)象;
    • 并且將這個(gè)exports對(duì)象賦值給了bar變量;
    • bar變量就是exports對(duì)象了;

    5.1 理解對(duì)象的引用賦值

    • 對(duì)象引用賦值

    5.2 畫圖解析賦值的過程

    • 對(duì)象引用指向共同的堆棧

    5.3 它們實(shí)際上是一個(gè)淺層拷貝

    • 為了進(jìn)一步論證,bar和exports是同一個(gè)對(duì)象:
      • 所以,bar對(duì)象是exports對(duì)象的淺拷貝(引用賦值);
      • 淺拷貝的本質(zhì)就是一種引用的賦值而已;


        淺層拷貝

6、module.exports又是什么?

  • 但是Node中我們經(jīng)常導(dǎo)出東西的時(shí)候,又是通過module.exports導(dǎo)出的:
    • <font color=red>module.exports和exports有什么關(guān)系或者區(qū)別呢?</font>
  • 我們追根溯源,通過維基百科中對(duì)CommonJS規(guī)范的解析:
    • CommonJS中是沒有module.exports的概念的;
    • 但是為了實(shí)現(xiàn)模塊的導(dǎo)出,Node中使用的是Module的類,每一個(gè)模塊都是Module的一個(gè)實(shí)例,也就是
      module;
    • 所以在Node中真正用于導(dǎo)出的其實(shí)根本不是exports,而是module.exports;
    • 因?yàn)?lt;font color=red>module才是導(dǎo)出的真正實(shí)現(xiàn)者</font>;
  • 但是,為什么exports也可以導(dǎo)出呢?
    • 這是因?yàn)閙odule對(duì)象的exports屬性是exports對(duì)象的一個(gè)引用;
    • 在node源碼內(nèi)部做了一個(gè)處理,module.exports = exports;
    • 也就是說 module.exports = exports = main中的bar;

    6.1 畫圖解析賦值的過程

    • 對(duì)象引用
    • module.exports賦值成對(duì)象,重新開辟一塊空間

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

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