<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【總結】1775- 聊聊前端模塊化

          共 7834字,需瀏覽 16分鐘

           ·

          2023-08-18 06:14

          前言

          在上古時期,曾經(jīng)的 Web 開發(fā)者們,應該會因為在一個龐大的 JavaScript 文件中尋找一個小小的函數(shù)而感到絕望?或者因為修改一個變量而不得不查找整個代碼庫?

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

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

          什么是模塊化

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

          為什么需要前端模塊化

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

          1. 可維護性差:當應用程序變得越來越大時,代碼變得越來越難以維護。
          2. 可重用性差:相同的代碼可能會被多次復制和粘貼到不同的文件中,這樣會導致代碼冗余,增加了代碼量。
          3. 可測試性差:在傳統(tǒng)的前端開發(fā)中,很難對代碼進行單元測試。
          4. 可擴展性差:在傳統(tǒng)的前端開發(fā)中,很難對應用程序進行擴展。
          前端模塊化的演進歷程

          全局 function 模式

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

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

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

          全局 namespace 模式

          既然全局 function 模式下,會有命名沖突等問題,那么我們可以通過對象來封裝模塊

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

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

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

                
                function(global{
             var data = 1

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

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

          IIFE 模式增強,傳入自定義依賴

          我們可以通過傳入依賴的方式來解決模塊間引用的問題

                
                function(global, otherModule{
             var data = 1

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

          缺陷:但仍然有以下幾個缺點

          1. 多依賴傳入時,代碼閱讀困難
          2. 無法支持大規(guī)模模塊化開發(fā)
          3. 無特定語法支持,代碼簡陋

          經(jīng)過以上過程的演進,我們確實可以實現(xiàn)前端模塊化開發(fā)了,但是仍然有幾個問題,一是請求過多,我們都是通過 script 標簽來引入各個模塊文件的,依賴多個模塊,那樣就會發(fā)送多個請求。二是依賴模糊,很容易因為不了解模塊之間的依賴關系導致加載先后順序出錯,模塊之間的依賴關系比較難以管理,也沒有明確的接口和規(guī)范。因此模塊化規(guī)范應運而生。

          模塊化規(guī)范

          CommonJS

          1. 概述

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

          2. 模塊的基本結構

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

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

          3. 模塊的加載方式

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

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

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

          4. 模塊的導出和導入方式

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

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

                
                // 導出一個變量
          module.exports.name = 'Tom';

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

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

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

          // 訪問其他模塊導出的變量
          console.log(moduleA.name);

          // 訪問其他模塊導出的函數(shù)
          moduleA.sayHello();

          5. 特點

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

          ES6 模塊化

          1. 概述

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

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

          ESModule 的模塊解析規(guī)則是基于 URL 解析規(guī)則的。當我們使用 import 語句導入一個模塊時,模塊加載器會根據(jù) import 語句中指定的路徑解析出對應的 URL,并將其作為唯一標識符來加載對應的模塊文件。在瀏覽器中,URL 解析規(guī)則是基于當前頁面的 URL 進行解析;在 Node.js 中,URL 解析規(guī)則是基于當前運行腳本的路徑進行解析。

          2. 模塊的加載方式

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

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

          3. 模塊的導出和導入方式

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

          • 命名導出和命名導入

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

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

          // app.js
          import { name, sayHello } from './module';
          • 默認導出和默認導入

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

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

          // app.js
          import message from './module';
          • 混合命名和默認導出

          混合命名和默認導出也是一種常見的方式,可以將多個變量或者函數(shù)命名導出,同時將一個變量或者函數(shù)作為默認導出。

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

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

          4. 特點:

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

          AMD

          1. 概述

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

          2. 基本語法

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

                
                define(id?, dependencies?, factory);

          其中:

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

          一個典型的 AMD 模塊定義如下所示:

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

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

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

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

          CMD

          1. 概述

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

          2. 基本語法

                
                //定義沒有依賴的模塊
          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ī)范專門用于瀏覽器端,模塊的加載是異步的,模塊使用時才會加載執(zhí)行。CMD 規(guī)范整合了 CommonJS 和 AMD 規(guī)范的特點。


          往期回顧
          #

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

          #

          11 個需要避免的 React 錯誤用法

          #

          6 個 Vue3 開發(fā)必備的 VSCode 插件

          #

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

          #

          6 個你必須明白 Vue3 的 ref 和 reactive 問題

          #

          6 個意想不到的 JavaScript 問題

          #

          試著換個角度理解低代碼平臺設計的本質(zhì)

          73f4b70b81d39d00bdf0604e817a860f.webp

          回復“加群”,一起學習進步

          瀏覽 47
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久狠狠干 | 豆花无码AV在线 | 国产三级黄色片 | 天天干在线播放 | 性欧美7777777 亚洲成人无码免费观看 |