成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JS模塊化之JavaScript模塊化方案總結

開發 前端
本文包含兩部分,第一部分通過簡明的描述介紹什么是 CommonJS、AMD、CMD、UMD、ES Module 以及它們的常見用法,第二部分則根據實際問題指出在正常的 webpack 構建過程中該如何指定打包配置中的模塊化參數。

 JS模塊化之JavaScript 模塊化方案總結

 

 

本文包含兩部分,第一部分通過簡明的描述介紹什么是 CommonJS、AMD、CMD、UMD、ES Module 以及它們的常見用法,第二部分則根據實際問題指出在正常的 webpack 構建過程中該如何指定打包配置中的模塊化參數。

JavaScript 模塊化方案

模塊化這個話題在 ES6 之前是不存在的,因此這也被詬病為早期 JavaScript 開發全局污染依賴管理混亂問題的源頭。這類歷史淵源和發展概述在本文將不會提及,因此感興趣可以自行搜索 JavaScript 發展史進行了解。

直接進入正題,我們來看看常見的模塊化方案都有哪些以及他們都有哪些內容。

CommonJS

CommonJS 的一個模塊就是一個腳本文件,通過執行該文件來加載模塊。CommonJS 規范規定,每個模塊內部,module 變量代表當前模塊。這個變量是一個對象,它的 exports 屬性(即 module.exports)是對外的接口。加載某個模塊,其實是加載該模塊的 module.exports 屬性。

我們見過這樣的模塊引用

  1. var myModule = require('module'); 
  2. myModule.sayHello(); 

這是因為我們把模塊的方法定義在了模塊的屬性上:

  1. // module.js 
  2. module.exports.sayHello = function() { 
  3.  console.log('Hello '); 
  4. }; 
  5. // 如果這樣寫 
  6. module.exports = sayHello; 
  7. // 調用則需要改為 
  8. var sayHello = require('module'); 
  9. sayHello(); 

require 命令第一次加載該腳本時就會執行整個腳本,然后在內存中生成一個對象(模塊可以多次加載,但是在第一次加載時才會運行,結果被緩存),這個結果長成這樣:

  1.  id: '...'
  2.  exports: { ... }, 
  3.  loaded: true
  4.  ... 

Node.js 的模塊機制實現就是參照了 CommonJS 的標準。但是 Node.js 額外做了一件事,即為每個模塊提供了一個 exports 變量,以指向 module.exports,這相當于在每個模塊最開始,寫有這么一行代碼:

  1. var exports = module.exports; 

CommonJS 模塊的特點:

  • 所有代碼都運行在模塊作用域,不會污染全局作用域。
  • 獨立性是模塊的重要特點就,模塊內部最好不與程序的其他部分直接交互。
  • 模塊可以多次加載,但是只會在第一次加載時運行一次,然后運行結果就被緩存了,以后再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。
  • 模塊加載的順序,按照其在代碼中出現的順序。

AMD

CommonJS 規范很好,但是不適用于瀏覽器環境,于是有了 AMD 和 CMD 兩種方案。AMD 全稱 Asynchronous Module Definition,即異步模塊定義。它采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成之后,這個回調函數才會運行。除了和 CommonJS 同步加載方式不同之外,AMD 在模塊的定義與引用上也有所不同。

  1. define(id?, dependencies?, factory); 

AMD 的模塊引入由 define 方法來定義,在 define API 中:

  • id:模塊名稱,或者模塊加載器請求的指定腳本的名字;
  • dependencies:是個定義中模塊所依賴模塊的數組,默認為 [“require”, “exports”, “module”],舉個例子比較好理解,當我們創建一個名為 “alpha” 的模塊,使用了require,exports,和名為 “beta” 的模塊,需要如下書寫(示例1);
  • factory:為模塊初始化要執行的函數或對象。如果為函數,它應該只被執行一次。如果是對象,此對象應該為模塊的輸出值;
  1. // 示例1 
  2. define("alpha", ["require""exports""beta"], function (require, exports, beta) { 
  3.  exports.verb = function() { 
  4.  return beta.verb(); 
  5.  // 或者 
  6.  return require("beta").verb(); 
  7.  } 
  8. }); 

如果模塊定義不存在依賴,那么可以直接定義對象:

  1. define({ 
  2.  addfunction(x, y){ 
  3.  return x + y; 
  4.  } 
  5. }); 

而使用時我們依舊通過 require 關鍵字,它包含兩個參數,第一個數組為要加載的模塊,第二個參數為回調函數:

  1. require([module], callback); 

舉個例子:

  1. require(['math'], function (math) { 
  2.  math.add(2, 3); 
  3. }); 

CMD

CMD 全稱為 Common Module Definition,是 Sea.js 所推廣的一個模塊化方案的輸出。在 CMD define 的入參中,雖然也支持包含 id, deps 以及 factory 三個參數的形式,但推薦的是接受 factory 一個入參,然后在入參執行時,填入三個參數 require、exports 和 module:

  1. define(function(require, exports, module) { 
  2.  var a = require('./a'); 
  3.  a.doSomething(); 
  4.  var b = require('./b');  
  5.  b.doSomething(); 
  6.  ... 
  7. }) 

通過執行該構造方法,可以得到模塊向外提供的接口。在與 AMD 比較上存在兩個主要的不同點(來自玉伯回答):

  1. 對于依賴的模塊,AMD 是提前執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改成可以延遲執行(根據寫法不同,處理方式不同)。CMD 推崇 as lazy as possible.
  2. CMD 推崇依賴就近,AMD 推崇依賴前置。

如果說的不清楚,那么我們直接看上面的代碼用 AMD 該怎么寫:

  1. define(['./a''./b'], function(a, b) {  
  2.  a.doSomething(); 
  3.  b.doSomething(); 
  4.  ... 
  5. }) 

UMD

UMD,全稱 Universal Module Definition,即通用模塊規范。既然 CommonJs 和 AMD 風格一樣流行,那么需要一個可以統一瀏覽器端以及非瀏覽器端的模塊化方案的規范。

直接來看看官方給出的 jQuery 模塊如何用 UMD 定義的代碼:

  1. (function (factory) { 
  2.  if (typeof define === 'function' && define.amd) { 
  3.  // AMD. Register as an anonymous module. 
  4.  define(['jquery'], factory); 
  5.  } else if (typeof module === 'object' && module.exports) { 
  6.  // Node/CommonJS 
  7.  module.exports = function( root, jQuery ) { 
  8.  if ( jQuery === undefined ) { 
  9.  // require('jQuery'returns a factory that requires window to 
  10.  // build a jQuery instance, we normalize how we use modules 
  11.  // that require this pattern but the window provided is a noop 
  12.  // if it's defined (how jquery works) 
  13.  if ( typeof window !== 'undefined' ) { 
  14.  jQuery = require('jquery'); 
  15.  } 
  16.  else { 
  17.  jQuery = require('jquery')(root); 
  18.  } 
  19.  } 
  20.  factory(jQuery); 
  21.  return jQuery; 
  22.  }; 
  23.  } else { 
  24.  // Browser globals 
  25.  factory(jQuery); 
  26.  } 
  27. }(function ($) { 
  28.  $.fn.jqueryPlugin = function () { return true; }; 
  29. })); 

UMD的實現很簡單:

  • 先判斷是否支持 AMD(define 是否存在),存在則使用 AMD 方式加載模塊;
  • 再判斷是否支持 Node.js 模塊格式(exports 是否存在),存在則使用 Node.js 模塊格式;
  • 前兩個都不存在,則將模塊公開到全局(window 或 global);

ES Modules

當然,以上說的種種都是社區提供的方案,歷史上,JavaScript 一直沒有模塊系統,直到 ES6 在語言標準的層面上,實現了它。其設計思想是盡量的靜態化,使得編譯時就能確定模塊的依賴關系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時確定這些東西。比如,CommonJS 模塊就是對象,輸入時必須查找對象屬性。而 ES Modules 不是對象,而是通過 export 命令顯式指定輸出的代碼。

ES Modules 的模塊化能力由 export 和 import 組成,export 命令用于規定模塊的對外接口,import 命令用于輸入其他模塊提供的功能。我們可以這樣定義一個模塊:

  1. // 第一種方式 
  2. export var firstName = 'Michael'
  3. export var lastName = 'Jackson'
  4. export var year = 1958; 
  5. // 第二種方式 
  6. var firstName = 'Michael'
  7. var lastName = 'Jackson'
  8. var year = 1958; 
  9. export { firstName, lastName, year }; 

然后再這樣引入他們:

  1. import { firstName, lastName, year } from 'module'
  2. import { firstName as newName } from 'module'
  3. import * as moduleA from 'module'

除以上兩種命令外,還有一個 export default 命令用于指定模塊的默認輸出(一個模塊只能有一個默認輸出)。如果使用了 export default 語法,在 import 時則可以任意命名。由于 export default 命令的本質是將后面的值,賦給 default 變量,所以也可以直接將一個值寫在 export default 之后。當然,引用方式也存在多種:

  1. import { default as foo } from 'module'
  2. import foo from 'module'

需要注意的是 Modules 會自動采用嚴格模式,且 import 命令具有提升效果,會提升到整個模塊的頭部,首先執行。

延伸閱讀 JavaScript 模塊的循環加載

webpack 打包輸出配置

說完理論,來看看實際項目中遇到的問題。當我們開發完一個 JavaScript 模塊必然要經歷打包的流程,而在 webpack 配置中,通過指定 output 選項就可以告訴 webpack 如何輸出 bundle, asset 以及其他載入的內容。那么如何實現不同環境可兼容的構建呢?

  • import:通過 ES Modules 規范語法進入引入;
  • 變量:作為一個全局變量,比如通過 script 標簽來訪問;
  • this:通過 this 對象訪問;
  • window:在瀏覽器中通過 window 對象訪問;
  • UMD:在 AMD 或 CommonJS 通過 require 引入后訪問;

output 中有一個屬性叫做 libraryTarget,被用來指定如何暴露你的模塊的屬性。你可以這樣嘗試賦值給一個變量或者指定對象的屬性:

  1. // 加載完成后將模塊賦值給一個指定變量(默認值) 
  2.  libraryTarget: 'var'
  3.  ... 
  4. // 賦值為指定對象的一個屬性,比如 `this` 或者 `window` 
  5.  libraryTarget: "this"
  6.  // libraryTarget: "window"
  7.  ... 
  8. // 同樣的,若是指定 commonjs,那么便可以將模塊分配給 exports,這也意味著可以用于 CommonJS 環境: 
  9.  libraryTarget: "commonjs"
  10.  ... 

如果需要更完整的模塊化 bundle,以確保和各模塊系統兼容,那么可以這樣嘗試:

  1. // 內容分配給 module.exports 對象,用于 CommonJS 環境 
  2.  libraryTarget: 'commonjs2'
  3.  ... 
  4. // 暴露為 AMD 模塊,通過特定屬性引入 
  5.  libraryTarget: 'amd'
  6.  ... 
  7. // 所有模塊系統兼容的萬金油,可以在 CommonJS, AMD 環境下運行,或將模塊導出到 global 下的變量 
  8.  libraryTarget: 'umd'
  9.  ... 

因此,如果只看 output 內容,那么我的一個 webpack 生產環境配置可以寫成這樣:

  1. module.exports = { 
  2.  output: { 
  3.  // webpack 如何輸出結果的相關選項 
  4.  path: path.resolve(__dirname, "dist"), 
  5.  filename: 'index.js'
  6.  library: 'hijiangtao'
  7.  umdNamedDefine: true
  8.  libraryTarget: 'umd'
  9.  }, 

 

責任編輯:龐桂玉 來源: 今日頭條
相關推薦

2016-10-09 11:03:41

Javascript模塊化Web

2012-11-08 09:45:44

JavaScriptrequireJS

2015-11-23 09:50:15

JavaScript模塊化SeaJs

2020-05-12 08:39:50

JavaScript工具技術

2020-09-17 10:30:21

前端模塊化組件

2013-08-20 15:31:18

前端模塊化

2017-05-18 10:23:55

模塊化開發RequireJsJavascript

2015-10-10 11:29:45

Java模塊化系統初探

2022-03-11 13:01:27

前端模塊

2020-09-18 09:02:32

前端模塊化

2009-12-10 11:04:08

Java模塊化OSGiJigsaw

2017-04-10 14:23:01

typescriptjavascriptwebpack

2013-08-20 18:39:34

JavaScript模requireJS

2009-08-17 10:11:12

C# Windows

2018-03-21 21:31:28

Java9編程Java

2022-09-05 09:01:13

前端模塊化

2018-06-21 09:36:09

模塊化數據中心集中化

2012-11-08 10:21:41

JSrequireJavaScript

2017-05-18 11:43:41

Android模塊化軟件

2019-09-02 10:51:59

Python腳本語言程序員
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久五月婷 | 岛国av免费看 | 波多野结衣中文字幕一区二区三区 | 日韩欧美久久 | 中文字幕欧美一区 | 九九热精品视频 | 亚洲一区二区三区桃乃木香奈 | 亚洲精品日本 | 国产精品久久久久久久免费观看 | 日韩精品久久久久久 | 狠狠干影院 | 精品无码久久久久久国产 | 午夜视频网站 | 日本人做爰大片免费观看一老师 | 日韩在线不卡 | 国产区视频在线观看 | 日韩久久久久 | 色视频网站在线观看 | 亚洲毛片在线观看 | 一区二区三区免费 | 成人av片在线观看 | 国产精品日韩一区 | 成人高清在线视频 | 国产精品国产a | 日韩中文字幕在线视频 | 天堂在线网 | 免费观看成人性生生活片 | 午夜av一区二区 | 国产精品激情小视频 | 在线观看黄视频 | 秋霞a级毛片在线看 | 黄色免费观看网站 | 夏同学福利网 | 亚洲最大的黄色网址 | 成人影院网站ww555久久精品 | 亚洲情综合五月天 | 国产精品a久久久久 | 久久久国产一区二区 | 91av亚洲| 久久精品国内 | 国产精品av久久久久久久久久 |