JS: 模塊化

来源:https://www.cnblogs.com/guolao/archive/2019/02/26/10440906.html
-Advertisement-
Play Games

模塊化 目前比較流行的 JS 模塊化方案有 CommonJS、AMD、CMD 以及 ES6 Module,還有個 UMD 方案。 CommonJS CommonJS 是伺服器端的模塊化方案,nodeJs 就採用了這種方案。在 CommonJS 規範中,一個文件即一個模塊,用 和`exports re ...


模塊化

目前比較流行的 JS 模塊化方案有 CommonJS、AMD、CMD 以及 ES6 Module,還有個 UMD 方案。

CommonJS


CommonJS 是伺服器端的模塊化方案,nodeJs 就採用了這種方案。在 CommonJS 規範中,一個文件即一個模塊,用module.exportsexports定義模塊輸出的介面,用require載入模塊。

// math.js
function add(a, b) {
  return a+b;
}

module.exports = {
    add: add
}

// 也可以這樣寫
exports.add = (a, b) => a+b;
// main.js
const math = require('./math');
math.add(1, 2); // 3

CommonJs採用同步載入方式,對於伺服器和本地環境來說,同步載入是非常快的,但對於瀏覽器來說,就不行了,限於網路因素,非同步載入才是比較好的方案。

AMD


為瞭解決瀏覽器模塊化的問題,AMD 和 CMD 這兩個非同步載入方案被提出,requireJS可以說是 AMD 方案的最佳實踐。

// index.html
// before
<script src="..."></script>
<script src="..."></script>
<script src="..."></script>
    
// AMD - requireJS
<script src="require.js" data-main="main.js"></script>

在 requireJS 中用define定義模塊,require載入模塊,require.config用來配置路徑。

// math.js
// define(id?, dependencies?, factory)
define(() => {
  return {
    add: (a, b) => a+b
  }
});
// main.js
require.config({
    baseUrl: 'js/lib',
    paths: {
        // 左邊是模塊ID,右邊是路徑
        // 這裡的路徑是 js/lib/jquery.js
        jquery: 'jquery',
        // 這裡的路徑是 js/lib/math.js
        math: 'math'
    }
});

// require([modlue], callback)
require(['jquery', 'math'], ($, math) => {
  // do something
});

需要註意的是,AMD 方案是依賴前置的,提前執行。

// AMD 依賴前置,提前執行
define(['a', 'b'], function(a, b){
    // a 和 b誰先載入完,誰就先執行
    // 並不按照代碼順序同步執行
    a.doSomething();
    b.doSomething();
})

官網:requireJS

CMD


與 AMD 不同,CMD 是依賴就近,延遲執行,requireJS 也支持 CMD 寫法。

// CMD 依賴就近,延遲執行
define(function(require, exports, module){
    // 需要 a 時,才執行 a
    var a = require("a");
    a.doSomething();
    // 需要 b 時,才執行 b
    var b = require("b");
    b.doSomething()
})

阿裡的 seaJS 可以說是比較出名的 CMD 實例項目,但現在都有更好的方案來替代它們了。

需要註意的是,兩者只是對依賴模塊的執行時機不一樣,並非載入時機不一樣,模塊的載入時機都是一樣的,它們都是非同步載入的。AMD是模塊載入完就會執行模塊,所有模塊都載入執行完就進入require的回調函數,CMD 則是所有模塊都載入完,但不執行,等到require這個模塊時才執行。

CMD標準:https://github.com/cmdjs
AMD標準:https://github.com/amdjs

UMD


UMD 是 CommonJS 和 AMD 的混合,它會判斷當前環境支持哪個就使用哪個,這個就不多說了。

ES6 Module


ES6 Module 橫空出世,混亂的時代結束了。

ES6 在語言標準層面定義模塊化規範,而且簡潔明瞭,完全可以取代 CommonJS 和 AMD 規範,成為瀏覽器和伺服器通用的模塊解決方案。

ES6 Module 主要使用export輸出,import載入。

// math.js
let PI = 3.1415;
let circleArea = (x) => x*PI;

export {PI, circleArea};

// 也可以這樣寫
export let PI = 3.1415;
export let circleArea = (x) => x*PI;
// main.js
import {PI, circleArea} from './math.js'
circleArea(1); // 3.1415

// 也可以這樣寫
import * as math from './math.js'
math.circleArea(1); // 3.1415

還有一個export default命令:

// 使用 export default 輸出的模塊只能有一個輸出
export default () => concole.log('hhh');

需要註意的是,CommonJS 輸出的是值的拷貝,對於基本數據類型是直接拷貝,即緩存模塊,但複雜數據類型是淺拷貝,因此修改一個模塊中的值,是會改變另一個模塊的值的。 require模塊的時候,就會執行整個模塊,即運行時載入,然後exports輸出,緩存輸出值,再次require時,會直接在緩存內取值。

而 ES6 Module 是編譯時載入,import載入的是值的引用,載入進來的值是不能被修改的,即值是只讀的,而且不論是基本數據類型還是複雜數據類型,修改原模塊的值修改,import得到的值也是會改變,即值是動態的

  • CommonJS 輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。
  • CommonJS 是運行時載入,ES6 模塊是編譯時輸出介面。

至於迴圈載入問題(a 依賴 b,b 依賴 c,c 依賴 a):

CommonJS 迴圈載入時,因為是屬於載入時執行,所以一旦出現某個模塊被"迴圈載入",就只輸出已經執行的部分,還未執行的部分就不輸出。而對於 ES6 Module來說,因為是動態引用,所以出現迴圈載入時,只要兩個模塊之間存在某個引用,即取值的時候能夠真正的取到值,代碼就能夠執行。

// node 環境
// a.mjs
import {bar} from './b';
console.log('a.mjs');
console.log(bar());
function foo() { return 'foo' }
export {foo};

// b.mjs
import {foo} from './a';
console.log('b.mjs');
console.log(foo());
function bar() { return 'bar' }
export {bar};
/* 結果
b.mjs
foo
a.mjs
bar
*/

執行a.mjs不會報錯,因為函數聲明會提升,在執行import {bar} from './b'時,函數foo就已經有定義了,所以b.mjs載入的時候不會報錯。這也意味著,如果把函數foo改寫成函數表達式,也會報錯。

備註


規範真多,但我也只用過 CommonJS 和 ES6 Module,而且 ES6 還要靠 babel

參考


JavaScript 模塊化七日談

阮一峰_Module 的語法

阮一峰_Module 的載入實現


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • (1)跨文檔事務支持 (ACID) 首個支持跨文檔事務的NoSQL雲資料庫,將文檔模型的速度,靈活性和功能與ACID保證相結合。現在,使用MongoDB解決各種用例變得更加容易。 (2)40%遷移速度提升 併發的讀取和寫入,使得新增分片shard遷移性能提升了約 40%, 新增節點能更快的承載業務壓 ...
  • 1.Build Setting>>>C Language Dialect,然後選擇GNU99[-std=gnu99] (選擇看項目實際要求)。 2.Build Setting>>>Architectures>>>Vaild Architectures,然後把arm64和armv7s去掉。 3.Bui ...
  • 首先參照官方文檔進行搭建Mac下的環境 ,然後就會遇到以下問題: 1.在下載了Flutter 之後,執行Flutter doctor之後,報錯: Could not resolve URL "https://pub.flutter-io.cn". Could not resolve URL "htt ...
  • ContentProvider ContentProvider 在android中的作用是對外共用數據,也就是說你可以通過ContentProvider把應用中的數據共用給其他應用訪問,其他應用可以通過ContentProvider 對你應用中的數據進行添刪改查。ContentProvider的就是 ...
  • 1、Activity的生命周期 1.1、典型情況下的生命周期 在有用戶參與的情況下,Activity所經過的生命周期的改變。 Activity會經歷如下生命周期: onCreate onRestart onStart onResume onPause onStop onDestroy 1.2、異常情 ...
  • VirtualApk引入步驟: 一、宿主應用引入VirtualApk 1、在項目的build.gradle文件中加入依賴: dependencies { classpath 'com.didi.virtualapk:gradle:0.9.8.6' } 完整的gradle文件如下: // Top le ...
  • 因為是v-for 迴圈 出來的,:key = "index" 會出現問題,所以,需要把:key="XXX"換成其他屬性就好了。 鏈接參考: https://segmentfault.com/q/1010000008276837 https://cn.vuejs.org/v2/guide/list.h ...
  • 1. 元素類名更改 2. mui下的fonts文件夾中添加mui-icons-extra.ttf文件 3. mui下的css文件中添加icons-extra.css文件 4. main.js中導入import './lib/mui/css/icons-extra.css' ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...