JS通用模塊寫法


模塊化這個問題並非一開始就存在,WWW剛剛問世的時候,html,JavaScript,CSS(JS和CSS都是后來在網景被引進瀏覽器的)都是極其簡單的存在,不需要模塊化。

模塊化的需求是規模的產物,當web page進化到web application,瀏覽器端處理的邏輯越來越復雜,展現的樣式和動畫越來多,對於工程的要求也就越來越高。於是模塊化的需求也就產生了。模塊化的意義:

  • 組件的復用,降低開發成本和維護成本
  • 組件單獨開發,方便分工合作
  • 模塊化遵循標准,方便自動化依賴管理,代碼優化,部署

JavaScript長久以來被認為是簡單的腳本語言,實際上情況早就發生來變化,在最新版的ECMA-262(ES6)文檔中強調JavaScript是通用編程語言而不是腳本語言。腳本語言,比如shell並不是用來完成復雜功能的,只是用來做一些自動化控制,是不需要模塊化的。而用於構建復雜系統通用編程語言(比如Java)一般都有模塊的實現。

在ES6以前,JS語言沒有模塊化,如何讓JS不止運行在瀏覽器,且能更有效的管理代碼,

於是應運而生CommonJS這種規范,定義了三個全局變量:

require,exports,module

require 用於引入一個模塊

exports 對外暴露模塊的接口,可以是任何類型

module 是這個模塊本身的對象

用require引入時獲取的是這個模塊對外暴露的接口(exports)

Node.js 使用了CommonJS規范:

var foo = require('foo')
var out = foo.sayName()
module.exports = out

在瀏覽器端,不像Node.js內部支持CommonJS,如何進行模塊化,

於是出現了 CMD 與 AMD 兩種方式,其主要代表是 seajs 和 requirejs,

他們都定義了一個全局函數 define 來創建一個模塊:

//CMD
define(function(require,exports,module){
  var foo = require('foo')
  var out = foo.sayName()
  module.exports = out
})

//AMD
define(['foo'],function(foo){
 var out = foo.sayName()
 return out;
})

可以看出CMD完好的保留了CommonJS的風格,

而AMD用了一種更簡潔的依賴注入和函數返回的方式實現模塊化。

兩者除風格不同外最大區別在於加載依賴模塊的方式,

CMD是懶加載,在require時才會加載依賴,

而AMD是預加載,在定義模塊時就提前加載好所有依賴。

我們要實現一個模塊,讓它既能在seajs(CMD)環境里引入,又能在requirejs(AMD)環境中引入,當然也能在Node.js(CommonJS)中使用,另外還可以在沒有模塊化的環境中用script標簽全局引入.

首先搞一個模塊

var factory = function(){
  var moduleName = {}
  return moduleName
}

當然 return 輸出的可以是任何值,對象,類,其他都可以

首先滿足Node.js 或者 ES6,我們可以通過全局變量module 和 exports 來判斷

var factory = function(){
  var moduleName = {}
  return moduleName
}
if(typeof module !=='undefined' && typeof exports ==='object'){
  module.exports = factory
}

在CMD和AMD 中,我們需要提供一個工廠函數傳入define來定義模塊,當沒有上述全局變量,且有define全局變量時,我們認為是AMD或CMD,可以直接將factory傳入define:

var factory = function(){
  var moduleName = {}
  return moduleName
}
if(typeof module !=='undefined' && typeof exports ==='object'){
  module.exports = factory
}else if(typeof define ==='function' && (define.cmd || define.amd)){
  define(factory)
} 

注意:CMD其實也支持return返回模塊接口,所以兩者可以通用。

然后還要滿足script標簽全局引入,我們可以將模塊放在window上,為了模塊內部在瀏覽器和Node.js中都能使用全局對象,我們可以做此判斷:

var global = typeof window !== 'undefined' ? window : global;

我們用一個立刻執行的閉包函數將所有代碼包含,來避免污染全局空間,並將global對象傳入閉包函數,最終變成這樣:

;(function(global){
  var factory = function(){
    var moduleName = {}
    return moduleName
  }
  if(typeof module !=='undefined' && typeof exports ==='object'){
    module.exports = factory
  }else if(typeof define ==='function' && (define.cmd || define.amd)){
    define(factory)
  }else{
    global.factory = factory
  }
})(typeof window !== 'undefined' ? window : global);

注意:閉包前加上分號是為了給前一個模塊填坑,分號多了沒問題,少了則語句可能發生變化。

然后,就能愉快的調用了

//Node.js
var myModule = require('moduleName')

//Seajs
define(function(require,exports,module){
  var myModule = require('moduleName')
})

// Browser global
<script src='moduleName.js'></script>

[完]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM