1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【總結(jié)】1775- 聊聊前端模塊化

        共 7834字,需瀏覽 16分鐘

         ·

        2023-08-18 06:14

        前言

        在上古時(shí)期,曾經(jīng)的 Web 開(kāi)發(fā)者們,應(yīng)該會(huì)因?yàn)樵谝粋€(gè)龐大的 JavaScript 文件中尋找一個(gè)小小的函數(shù)而感到絕望?或者因?yàn)樾薷囊粋€(gè)變量而不得不查找整個(gè)代碼庫(kù)?

        當(dāng)下的前端開(kāi)發(fā)中,webpack,rollup,vite 等構(gòu)建打包工具大家應(yīng)該都用的飛起了。它們都基于一個(gè)非常重要的概念 - 前端模塊化。

        在這篇文章中,我們將聊聊前端模塊化的發(fā)展歷程以及主流的一些方案。

        什么是模塊化

        前端模塊化是指將一個(gè)大型的前端應(yīng)用程序分解為小的、獨(dú)立的模塊,每個(gè)模塊都有自己的功能和接口,可以被其他模塊使用。前端模塊化的出現(xiàn)是為了解決前端開(kāi)發(fā)中代碼復(fù)雜度和可維護(hù)性的問(wèn)題。在前端模塊化的架構(gòu)下,開(kāi)發(fā)人員可以更加專注于各自的模塊開(kāi)發(fā),提高了代碼的復(fù)用性和可維護(hù)性。

        為什么需要前端模塊化

        在傳統(tǒng)的前端開(kāi)發(fā)中,所有的代碼都是寫在同一個(gè)文件中,這樣做的問(wèn)題在于:

        1. 可維護(hù)性差:當(dāng)應(yīng)用程序變得越來(lái)越大時(shí),代碼變得越來(lái)越難以維護(hù)。
        2. 可重用性差:相同的代碼可能會(huì)被多次復(fù)制和粘貼到不同的文件中,這樣會(huì)導(dǎo)致代碼冗余,增加了代碼量。
        3. 可測(cè)試性差:在傳統(tǒng)的前端開(kāi)發(fā)中,很難對(duì)代碼進(jìn)行單元測(cè)試。
        4. 可擴(kuò)展性差:在傳統(tǒng)的前端開(kāi)發(fā)中,很難對(duì)應(yīng)用程序進(jìn)行擴(kuò)展。
        前端模塊化的演進(jìn)歷程

        全局 function 模式

        將不同功能封裝成不同的函數(shù)

              
              function fetchData() {
            ...
        }
        function handleData() {
           ...
        }

        缺陷:這個(gè)是將方法掛在 window 下,會(huì)污染全局命名空間,容易引起命名沖突且數(shù)據(jù)不安全等問(wèn)題。

        全局 namespace 模式

        既然全局 function 模式下,會(huì)有命名沖突等問(wèn)題,那么我們可以通過(guò)對(duì)象來(lái)封裝模塊

              
              var myModule = {
         fetchData() {
            ...
        },
         handleData() {
           ...
        }
        };

        缺陷:這個(gè)方案確實(shí)減少了全局變量,解決命名沖突的問(wèn)題,但是外部可以直接修改模塊內(nèi)部的數(shù)據(jù)。

        IIFE 模式,通過(guò)自執(zhí)行函數(shù)創(chuàng)建閉包

              
              function(global{
           var data = 1

           function fetchData() {
                ...
           }
           function handleData() {
               ...
           }
           window.myModule = {fetchData, handleData}
        }(window)

        缺陷:這個(gè)方案下,數(shù)據(jù)是私有的,外部只能通過(guò)暴露的方法操作,但無(wú)法解決模塊間相互依賴問(wèn)題。

        IIFE 模式增強(qiáng),傳入自定義依賴

        我們可以通過(guò)傳入依賴的方式來(lái)解決模塊間引用的問(wèn)題

              
              function(global, otherModule{
           var data = 1

           function fetchData() {
                ...
           }
           function handleData() {
               ...
           }
           window.myModule = {fetchData, handleData, otherApi: otherModule.api}
        }(windowwindow.other_module)

        缺陷:但仍然有以下幾個(gè)缺點(diǎn)

        1. 多依賴傳入時(shí),代碼閱讀困難
        2. 無(wú)法支持大規(guī)模模塊化開(kāi)發(fā)
        3. 無(wú)特定語(yǔ)法支持,代碼簡(jiǎn)陋

        經(jīng)過(guò)以上過(guò)程的演進(jìn),我們確實(shí)可以實(shí)現(xiàn)前端模塊化開(kāi)發(fā)了,但是仍然有幾個(gè)問(wèn)題,一是請(qǐng)求過(guò)多,我們都是通過(guò) script 標(biāo)簽來(lái)引入各個(gè)模塊文件的,依賴多個(gè)模塊,那樣就會(huì)發(fā)送多個(gè)請(qǐng)求。二是依賴模糊,很容易因?yàn)椴涣私饽K之間的依賴關(guān)系導(dǎo)致加載先后順序出錯(cuò),模塊之間的依賴關(guān)系比較難以管理,也沒(méi)有明確的接口和規(guī)范。因此模塊化規(guī)范應(yīng)運(yùn)而生。

        模塊化規(guī)范

        CommonJS

        1. 概述

        CommonJS 是一個(gè) JavaScript 模塊化規(guī)范,它最初是為了解決 JavaScript 在服務(wù)器端的模塊化問(wèn)題而提出的。是 NodeJS 的默認(rèn)模塊飯規(guī)范,該規(guī)范定義了模塊的基本結(jié)構(gòu)、模塊的加載方式以及模塊的導(dǎo)出和導(dǎo)入方式等內(nèi)容。

        2. 模塊的基本結(jié)構(gòu)

        在 CommonJS 規(guī)范中,一個(gè)模塊就是一個(gè)文件。每個(gè)文件都是一個(gè)獨(dú)立的模塊,文件內(nèi)部定義的變量、函數(shù)和類等只在該文件內(nèi)部有效。

        每個(gè)模塊都有自己的作用域,模塊內(nèi)部的變量、函數(shù)和類等只在該模塊內(nèi)部有效。如果想在其他模塊中使用該模塊內(nèi)部的變量、函數(shù)和類等,需要將其導(dǎo)出。

        3. 模塊的加載方式

        在 CommonJS 規(guī)范中,模塊的加載方式是同步的。也就是說(shuō),當(dāng)一個(gè)模塊被引入時(shí),會(huì)立即執(zhí)行該模塊內(nèi)部的代碼,并將該模塊導(dǎo)出的內(nèi)容返回給引入該模塊的代碼。

        模塊可以多次加載,第一次加載時(shí)會(huì)運(yùn)行模塊,模塊輸出結(jié)果會(huì)被緩存,再次加載時(shí),會(huì)從緩存結(jié)果中直接讀取模塊輸出結(jié)果。模塊加載的順序,按照其在代碼中出現(xiàn)的順序。模塊輸出的值是值的拷貝,類似 IIFE 方案中的內(nèi)部變量

        這種同步加載方式可以保證模塊內(nèi)部的代碼執(zhí)行完畢后再執(zhí)行外部代碼,從而避免了異步加載所帶來(lái)的一些問(wèn)題。但同時(shí)也會(huì)影響頁(yè)面加載速度,因此在瀏覽器端使用時(shí)需要注意。

        4. 模塊的導(dǎo)出和導(dǎo)入方式

        在 CommonJS 規(guī)范中,一個(gè)模塊可以通過(guò)module.exports 或者 exports 對(duì)象來(lái)導(dǎo)出內(nèi)容。module.exports 是真正的導(dǎo)出對(duì)象,而 exports 對(duì)象只是對(duì) module.exports 的一個(gè)引用。

        一個(gè)模塊可以導(dǎo)出多個(gè)內(nèi)容,可以通過(guò) module.exports 或者 exports 對(duì)象分別導(dǎo)出。例如:

              
              // 導(dǎo)出一個(gè)變量
        module.exports.name = 'Tom';

        // 導(dǎo)出一個(gè)函數(shù)
        exports.sayHello = function() {
          console.log('Hello!');
        };

        在另一個(gè)模塊中,可以通過(guò) require 函數(shù)來(lái)引入其他模塊,并訪問(wèn)其導(dǎo)出的內(nèi)容。例如:

              
              // 引入其他模塊
        var moduleA = require('./moduleA');

        // 訪問(wèn)其他模塊導(dǎo)出的變量
        console.log(moduleA.name);

        // 訪問(wèn)其他模塊導(dǎo)出的函數(shù)
        moduleA.sayHello();

        5. 特點(diǎn)

        • CommonJS 模塊由 JS 運(yùn)行時(shí)實(shí)現(xiàn)。
        • CommonJS 模塊輸出的是值的拷貝,本質(zhì)上導(dǎo)出的就是 exports 屬性。
        • CommonJS 是可以動(dòng)態(tài)加載的,對(duì)每一個(gè)加載都存在緩存,可以有效的解決循環(huán)引用問(wèn)題。
        • CommonJS 模塊同步加載并執(zhí)行模塊文件。

        ES6 模塊化

        1. 概述

        在 ES6 之前,JavaScript 并沒(méi)有原生支持模塊化,因此開(kāi)發(fā)者們需要使用一些第三方庫(kù)或者自己實(shí)現(xiàn)一些模塊化方案來(lái)解決代碼復(fù)用和管理問(wèn)題。但是這些方案都有一些問(wèn)題,比如命名沖突、依賴管理等。ES6 引入了 ESModule 模塊化規(guī)范來(lái)解決這些問(wèn)題。

        ESModule 模塊化規(guī)范是一種靜態(tài)的模塊化方案,它允許開(kāi)發(fā)者將代碼分割成小的、獨(dú)立的模塊,每個(gè)模塊都有自己的作用域。ESModule 規(guī)范是基于文件的,每個(gè)文件都是一個(gè)獨(dú)立的模塊。

        ESModule 的模塊解析規(guī)則是基于 URL 解析規(guī)則的。當(dāng)我們使用 import 語(yǔ)句導(dǎo)入一個(gè)模塊時(shí),模塊加載器會(huì)根據(jù) import 語(yǔ)句中指定的路徑解析出對(duì)應(yīng)的 URL,并將其作為唯一標(biāo)識(shí)符來(lái)加載對(duì)應(yīng)的模塊文件。在瀏覽器中,URL 解析規(guī)則是基于當(dāng)前頁(yè)面的 URL 進(jìn)行解析;在 Node.js 中,URL 解析規(guī)則是基于當(dāng)前運(yùn)行腳本的路徑進(jìn)行解析。

        2. 模塊的加載方式

        ESModule 規(guī)范是基于文件的,每個(gè)文件都是一個(gè)獨(dú)立的模塊。在瀏覽器中,可以使用<script type="module">標(biāo)簽來(lái)加載 ESModule 模塊。在 Node.js 中,可以使用 import 關(guān)鍵字來(lái)加載 ESModule 模塊。

              
              
                <!-- 在瀏覽器中加載ESModule模塊 -->
                
        <script type="module" src="./module.js"> </script>
              
              // 在Node.js中加載ESModule模塊
        import { name } from './module';

        3. 模塊的導(dǎo)出和導(dǎo)入方式

        在 ESModule 中,使用 export 關(guān)鍵字將變量或者函數(shù)導(dǎo)出,使用 import 關(guān)鍵字導(dǎo)入其他模塊中導(dǎo)出的變量或者函數(shù)。導(dǎo)出和導(dǎo)入方式有以下幾種:

        • 命名導(dǎo)出和命名導(dǎo)入

        命名導(dǎo)出和命名導(dǎo)入是最常見(jiàn)的一種方式。可以將多個(gè)變量或者函數(shù)命名導(dǎo)出,也可以將多個(gè)變量或者函數(shù)命名導(dǎo)入。

              
              // module.js
        export const name = '張三';
        export function sayHello() {
          console.log('Hello');
        }

        // app.js
        import { name, sayHello } from './module';
        • 默認(rèn)導(dǎo)出和默認(rèn)導(dǎo)入

        默認(rèn)導(dǎo)出和默認(rèn)導(dǎo)入是一種簡(jiǎn)單的方式,可以將一個(gè)變量或者函數(shù)作為默認(rèn)導(dǎo)出,也可以將一個(gè)變量或者函數(shù)作為默認(rèn)導(dǎo)入。

              
              // module.js
        export default 'Hello World';

        // app.js
        import message from './module';
        • 混合命名和默認(rèn)導(dǎo)出

        混合命名和默認(rèn)導(dǎo)出也是一種常見(jiàn)的方式,可以將多個(gè)變量或者函數(shù)命名導(dǎo)出,同時(shí)將一個(gè)變量或者函數(shù)作為默認(rèn)導(dǎo)出。

              
              // module.js
        export const name = '張三';
        export function sayHello() {
          console.log('Hello');
        }
        export default 'Hello World';

        // app.js
        import message, { name, sayHello } from './module';

        4. 特點(diǎn):

        • ES6 Module 靜態(tài)的,不能放在塊級(jí)作用域內(nèi),代碼發(fā)生在編譯時(shí)。
        • ES6 模塊輸出的是值的引用,如果一個(gè)模塊修改了另一個(gè)模塊導(dǎo)出的值,那么這個(gè)修改會(huì)影響到原始模塊。
        • ES6 Module 可以導(dǎo)出多個(gè)屬性和方法,可以單個(gè)導(dǎo)入導(dǎo)出,混合導(dǎo)入導(dǎo)出。
        • ES6 模塊提前加載并執(zhí)行模塊文件,

        AMD

        1. 概述

        AMD 是 Asynchronous Module Definition 的縮寫,即異步模塊定義。它是由 RequireJS 的作者 James Burke 提出的一種模塊化規(guī)范。AMD 規(guī)范的主要特點(diǎn)是:異步加載、提前執(zhí)行。

        2. 基本語(yǔ)法

        在 AMD 規(guī)范中,一個(gè)模塊通常由以下幾個(gè)部分組成:

              
              define(id?, dependencies?, factory);

        其中:

        • id:可選參數(shù),表示模塊標(biāo)識(shí)符,一般為字符串類型。
        • dependencies:可選參數(shù),表示當(dāng)前模塊所依賴的其他模塊。它是一個(gè)數(shù)組類型,每個(gè)元素表示一個(gè)依賴模塊的標(biāo)識(shí)符。
        • factory:必需參數(shù),表示當(dāng)前模塊的工廠函數(shù)。它是一個(gè)函數(shù)類型,用于定義當(dāng)前模塊的行為。

        一個(gè)典型的 AMD 模塊定義如下所示:

              
              define('module1', ['module2''module3'], function(module2, module3{
          // 模塊1的代碼邏輯
          return {
            // 暴露給外部的接口
          };
        });

        AMD 規(guī)范采用異步加載方式,它通過(guò)require函數(shù)來(lái)加載一個(gè)或多個(gè)模塊。require函數(shù)接受一個(gè)數(shù)組類型的參數(shù),每個(gè)元素表示一個(gè)待加載的模塊標(biāo)識(shí)符。當(dāng)所有依賴模塊加載完成后,require函數(shù)才會(huì)執(zhí)行回調(diào)函數(shù)。

              
              require(['module1''module2'], function(module1, module2{
          // 所有依賴模塊加載完成后執(zhí)行的回調(diào)函數(shù)
        });

        AMD 模式可以用于瀏覽器環(huán)境,并且允許非同步加載模塊,也可以根據(jù)需要?jiǎng)討B(tài)加載模塊。

        CMD

        1. 概述

        CMD 是 Common Module Definition 的縮寫,即通用模塊定義。CMD 規(guī)范的主要特點(diǎn)是:按需加載、延遲執(zhí)行。

        2. 基本語(yǔ)法

              
              //定義沒(méi)有依賴的模塊
        define(function(require, exports, module){
          exports.xxx = value
          module.exports = value
        })
        //定義有依賴的模塊
        define(function(require, exports, module){
            //引入依賴模塊(同步)
            var module2 = require('./module2')
            //引入依賴模塊(異步)
            require.async('./module3'function (m3{
          })
            //暴露模塊
            exports.xxx = value
         })

         // 引入該模塊
         define(function (require{
          var m1 = require('./module1')
          var m4 = require('./module4')
          m1.show()
          m4.show()
        })

        CMD 規(guī)范專門用于瀏覽器端,模塊的加載是異步的,模塊使用時(shí)才會(huì)加載執(zhí)行。CMD 規(guī)范整合了 CommonJS 和 AMD 規(guī)范的特點(diǎn)。


        往期回顧
        #

        如何使用 TypeScript 開(kāi)發(fā) React 函數(shù)式組件?

        #

        11 個(gè)需要避免的 React 錯(cuò)誤用法

        #

        6 個(gè) Vue3 開(kāi)發(fā)必備的 VSCode 插件

        #

        3 款非常實(shí)用的 Node.js 版本管理工具

        #

        6 個(gè)你必須明白 Vue3 的 ref 和 reactive 問(wèn)題

        #

        6 個(gè)意想不到的 JavaScript 問(wèn)題

        #

        試著換個(gè)角度理解低代碼平臺(tái)設(shè)計(jì)的本質(zhì)

        73f4b70b81d39d00bdf0604e817a860f.webp

        回復(fù)“加群”,一起學(xué)習(xí)進(jìn)步

        瀏覽 47
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国精品人伦一区二区三区蜜桃 | 日韩成人性爱视频 | 魅影直播游客免登录 | 精品人伦一区二区三 | 潘金莲一级淫片aaaaaa在线 | 少妇高潮毛片免费看欧美一v | 台湾久久久久三极片 | 五月丁香色婷婷七月在线视频 | free大乳激情pics | 肏逼影视 |