一次搞懂 - JavaScript 模塊化詳解

作者:九旬

來源:SegmentFault 思否社區

模塊化的意義


將代碼拆分成獨立的塊,然後再把這些塊使用模塊模式連接起來實現不同的功能。

就像小時候玩的拼圖一樣,不同的拼圖組合在一起就可以拼成任意的形狀。

這種模式的背後思想也很簡單:把邏輯分塊、各自封裝,相互獨立,同時自行決定引入執行那些外部模塊以及暴露自身的那些模塊。

這個基本的思想是所有的 JavaScript 模塊系統的基礎。

文中代碼案例地址:

https://github.com/AnsonZnl/JS-Modules-Sample

模塊化的好處

JS 中常見的模塊

IIFE 模式:匿名函數自調用(閉包)

主要應用在瀏覽器端。

利用閉包的原理創造一個獨有的函數作用域來保存私有變量,達到模塊化的效果。

使用

HTML

<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
  console.log(myModule.get()); // output-data(獲取內部數據)
  myModule.set("new data"); // 設置內部數據
  console.log(myModule.data); //output-undefined (不能訪問模塊內部數據)
  myModule.data = "xxxx"; //不是修改的模塊內部的data
  console.log(myModule.get()); //output-new data 修改後的值
</script>

JS

// module.js文件
(function(window) {
  let data = "data";
  //獲取數據
  function get() {
    return data;
  }
  // 修改數據
  function set(val) {
    data = val;
  }
  //暴露行爲
  window.myModule = {
    get,
    set,
  };
})(window);

CommonJS

主要應用在服務端,如果在瀏覽器端運行需要藉助其他工具(Browserify)。

暴露模塊: module.exports = value或者exports.xx = value(exports 是一個導出的對象)

引入模塊: require(xx),如果是第三方模塊,xxx 爲模塊名,如果爲自定義模塊,xxx 爲模塊的文件路徑。

特點

使用
在 Node 中 安裝 uniq 函數。

npm init
npm install uniq --save
// module.js
let arr = [1, 2, 2, 3, 3];
module.exports = {
  arr,
};
// app.js
let module1 = require("./module.js");
let uniq = require("uniq");

console.log(uniq(module1.arr)); // [1,2,3]

AMD

全稱是 Asynchronous Module Definition - 異步模塊定義

和 CommonJS 不同的是 AMD 採用非同步的方式來加載模塊。

基本語法

定義暴露模塊

// 定義沒有依賴的模塊
define(function() {
  return 模塊;
});
// 定義有依賴的模塊
define(["module1""module2"]function(m1, m2) {
  return 模塊;
});

引入使用模塊

require(["module1""module2"]function(m1, m2) {
  使用m1 和 m2;
});

使用案例

<!-- index.html -->
<body>
  <!-- 引入require.js並指定js主文件的入口 -->
  <script
    data-main="main"
    src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
  ></script>
</body>
// main.js
(function() {
  require(["module.js"]function(module) {
    let currentUrl = module.getUrl();
    alert("當前頁面的URl:" + currentUrl);
  });
})();
// module.js
// 定義模塊
define(function() {
  let url = window.location.href;

  function getUrl() {
    return url.toUpperCase();
  }
  // 暴露模塊
  return {
    getUrl,
  };
});

更多的使用方法請參考:https://requirejs.org/

CMD

CMD--- 是 SeaJS 在推廣過程中對模塊定義的規範化產出,是一個同步模塊定義,是 SeaJS 的一個標準,SeaJS 是 CMD 概念的一個實現,SeaJS 是淘寶團隊提供的一個模塊開發的 JS 框架。

什麼時候用到什麼時候引入,即用即返回,這是一個同步概念。

特點: CMD 是 AMD 在基礎上改進的一種規範,和 AMD 不同在於依賴模塊的執行機制不同,CMD 是就近依賴,而 AMD 是前置依賴。

環境: 瀏覽器環境

語法:

使用

// main.js
define(function(require, exports, module) {
  var moduleA = require("./module.js");
  alert(moduleA.a); // 打印出:hello world
});
// module.js
define(function(require, exports, module) {
  exports.a = "hello world";
});
<body>
  <script
    data-main="main"
    src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
  ></script>
</body>

UMD

全稱 Universal Module Definition 看名字就知道,特點是兼容 AMD 和 CommonJS 規範,而且兼容全局引入。

環境: 服務器環境和瀏覽器端

UMD 實現原理很簡單:

使用

(function(root, factory) {
  if (typeof define === "function" && define.amd) {
    //AMD
    define(["jquery"], factory);
  } else if (typeof exports === "object") {
    //Node, CommonJS之類的
    module.exports = factory(require("jquery"));
  } else {
    //瀏覽器全局變量(root 即 window)
    root.returnExports = factory(root.jQuery);
  }
})(this, function($) {
  //方法
  function myFuncA() {} // 私有方法,因爲沒有返回
  function myFuncB() {} // 公共方法,因爲返回了

  //暴露公共方法
  return {
    myFuncB,
  };
});

大家平時引入的 jQuery 的 CND 就是 UMD 的,源碼可以查看:

https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js

ES6 Module

在 ES6 之前,模塊化主要是社區在推動進行的,從而出現了 CommonJS 和 AMD 兩個,前者用於服務器後者用於瀏覽器,ES6 模塊的出現將完全替代 CommonJS 和 AMD 規範,成爲瀏覽器和服務器通用的解決方案。

ES6 模塊的設計思想是儘量的靜態化,使得編譯時就能確定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時確定這些東西。比如,CommonJS 模塊就是對象,輸入時必須查找對象屬性。

特點 :

環境: 服務器環境和瀏覽器端

語法:

使用

Node 中 先安裝 Babel:

npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save @babel/polyfill
# 然後運行
npx babel-node main.js
// modules/double.js
let mes = "Hello Modules for double";
function sum(value) {
  return `${mes} - ${value * 2}`;
}
export default {
  mes,
  sum,
};
// main.js
import module from "./modules/double";
console.log(module.sum(10)); // Hello Modules for double - 20

瀏覽器中

區別

缺點
瀏覽器和服務器目前的支持不是很好,現階段使用需要藉助一些工具(Babel)。

最好不要兩者混用。更多的使用方法可以參考:https://es6.ruanyifeng.com/#d...

總結

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/5yC8Mv4mODLHiXCg2fQzAg