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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...