javascript模塊化

一、爲何要模塊化javascript

  嵌入網頁的javascript代碼愈來愈龐大,愈來愈複雜,須要一個團隊分工協做、進度管理、單元測試等,模塊化編程,已經成爲一個迫切的需求。此外:模塊化編程解決的問題有:命名衝突問題,文件依賴問題等等。html

一言以蔽之:模塊化就是分解代碼。java

二、什麼是模塊node

模塊就是實現特定功能的一組方法。只要把不一樣的函數(以及記錄狀態的變量)簡單地放在一塊兒,就算是一個模塊。有了模塊,咱們能夠更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊。接着出現了模塊規範:就是你們必須以一樣的方式編寫模塊,目前,通行的Javascript模塊規範主要有兩種:CommonJS和AMD。jquery

 

三、模塊之間的關係如何解決
web

 經過造成依賴樹來保證模塊的加載順序 
3.1:AMD規範中:若是模塊還依賴其餘模塊,那麼define()函數的第一個參數,必須是一個數組,指明該模塊的依賴性。
 define(['myLib'], function(myLib){     function foo(){       myLib.doSomething();     }     return {       foo : foo     };   });

3.2:CMD規範中:npm

// 全部模塊都經過 define 來定義
define(function(require, exports, module) { // 經過 require 引入依賴
  var $ = require('jquery'); var Spinning = require('./spinning'); // 經過 exports 對外提供接口
  exports.doSomething = ... // 或者經過 module.exports 提供整個接口
  module.exports = ... });

 

四、AMD和common js有什麼區別 編程

 

 AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"。它採用異步方式加載模塊,模塊的加載不影響它後面語句的運行。全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。json

  AMD也採用require()語句加載模塊,可是不一樣於CommonJS,它要求兩個參數:數組

    require([module], callback);

第一個參數[module],是一個數組,裏面的成員是要加載的模塊;

第二個參數callback,是加載成功以後的回調函數。若是將前面的代碼改寫成AMD形式,就是下面這樣:

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

 

CommonJS是服務器端模塊的規範,Node.js採用了這個規範。

根據CommonJS規範,一個單獨的文件就是一個模塊。加載模塊使用require方法,該方法讀取一個文件並執行,最後返回文件內部的exports對象。下面就是一個簡單的模塊文件example.js。

console.log("evaluating example.js"); var invisible = function () { console.log("invisible"); } exports.message = "hi"; exports.say = function () { console.log(message); }

 

使用require方法,加載example.js。

var example = require('./example.js');

 

這時,變量example就對應模塊中的exports對象,因而就能夠經過這個變量,使用模塊提供的各個方法。

{ message: "hi", say: [Function] }

 

require方法默認讀取js文件,因此能夠省略js後綴名。

var example = require('./example');

 

js文件名前面須要加上路徑,能夠是相對路徑(相對於使用require方法的文件),也能夠是絕對路徑。若是省略路徑,node.js會認爲,你要加載一個核心模塊,或者已經安裝在本地 node_modules 目錄中的模塊。若是加載的是一個目錄,node.js會首先尋找該目錄中的 package.json 文件,加載該文件 main 屬性提到的模塊,不然就尋找該目錄下的 index.js 文件。

下面的例子是使用一行語句,定義一個最簡單的模塊。

// addition.js
 exports.do = function(a, b){ return a + b };

 

上面的語句定義了一個加法模塊,作法就是在exports對象上定義一個do方法,那就是供外部調用的方法。使用的時候,只要用require函數調用便可。

var add = require('./addition'); add.do(1,2) // 3

 

再看一個複雜一點的例子。

// foobar.js

function foobar(){ this.foo = function(){ console.log('Hello foo'); } this.bar = function(){ console.log('Hello bar'); } } exports.foobar = foobar;

調用該模塊的方法以下:

var foobar = require('./foobar').foobar, test = new foobar(); test.bar(); // 'Hello bar'

有時,不須要exports返回一個對象,只須要它返回一個函數。這時,就要寫成module.exports。

module.exports = function () { console.log("hello world") }

總結:

1.common js是同步加載的 ,amd是異步的 

2.根本不一樣:common js用於服務器端同步加載模塊;amd是客戶端異步加載模塊。cmd  =瀏覽器端實現的蹩腳的common js (爲何這樣:由於http是異步的, 在瀏覽器端使用common js不現實,cmd=amd的思想+common js的寫法 )

3.相同點:二者都有一個全局函數require(),用於加載模塊;只是AMD規範中的require函數須要有2個參數。

 

五、包,以及npm包結構規範

5.1:概念包就是能完成獨立功能的一個特殊模塊 ,例如connect,http,compression,cookie-session,body-parser

都是包,包與模塊相比有多個區別:

 

一、包是由模塊組成的
二、一般狀況下由第三方提供的叫包,而本身書寫的叫模塊
三、一般引用包用模塊的名字,而引用模塊用文件路徑

 

四、模塊可能不能單獨使用,而包是能夠單獨使用的

官網解釋:package

This specification describes the CommonJS package format for distributing CommonJS programs and libraries. A CommonJS package is a cohesive wrapping of a collection of modules, code and other assets into a single form. It provides the basis for convenient delivery, installation and management of CommonJS components.

 

This specifies the CommonJS package descriptor file and package file format. It does not specify a package catalogue file or format; this is an exercise for future specifications. The package descriptor file is a statement of known fact at the time the package is published and may not be modified without publishing a new release. 

5.2:包結構規範

CommonJS包規範是理論,NPM是其中的一種實踐。NPM之於Node,至關於gem之於Ruby,pear之於PHP。對於Node而言,NPM幫助完成了第三方模塊的發佈、安裝和依賴等。藉助NPM,Node與第三方模塊之間造成了很好的一個生態系統。 藉助NPM,能夠幫助用戶快速安裝和管理依賴包。

一個符合CommonJS規範的包應該是以下這種結構:

  • 一個package.json文件應該存在於包頂級目錄下
  • 二進制文件應該包含在bin目錄下。
  • JavaScript代碼應該包含在lib目錄下。
  • 文檔應該在doc目錄下。
  • 單元測試應該在test目錄下。
  •  由上文的require的查找過程能夠知道,Node.js在沒有找到目標文件時,會將當前目錄看成一個包來嘗試加載,因此在package.json文件中最重要的一個字段就是main。而實際上,這一處是Node.js的擴展,標準定義中並不包含此字段,對於require,只須要main屬性便可。可是在除此以外包須要接受安裝、卸載、依賴管理,版本管理等流程,因此CommonJS爲package.json文件定義了以下一些必須的字段:
  • name。包名,須要在NPM上是惟一的。不能帶有空格。
  • description。包簡介。一般會顯示在一些列表中。
  • version。版本號。一個語義化的版本號(http://semver.org/ ),一般爲x.y.z。該版本號十分重要,經常用於一些版本控制的場合。
  • keywords。關鍵字數組。用於NPM中的分類搜索。
  • maintainers。包維護者的數組。數組元素是一個包含name、email、web三個屬性的JSON對象。
  • contributors。包貢獻者的數組。第一個就是包的做者本人。在開源社區,若是提交的patch被merge進master分支的話,就應當加上這個貢獻patch的人。格式包含name和email。如:
  • "contributors": [{ "name": "Jackson Tian", "email": "mail @gmail.com" }, { "name": "fengmk2", "email": "mail2@gmail.com" }],
  • bugs。一個能夠提交bug的URL地址。能夠是郵件地址(mailto:mailxx@domain),也能夠是網頁地址(http://url)。
  • licenses。包所使用的許可證。例如:
  • "licenses": [{ "type": "GPLv2", "url": "http://www.example.com/licenses/gpl.html", }]
  • repositories。託管源代碼的地址數組。
  • dependencies。當前包須要的依賴

六、node.js的模塊引用機制

 6.1:簡單模塊定義和使用

在Node.js中,定義一個模塊十分方便。咱們以計算圓形的面積和周長兩個方法爲例,來表現Node.js中模塊的定義方式。

var PI = Math.PI; exports.area = function (r) { return PI * r * r; }; exports.circumference = function (r) { return 2 * PI * r; };

將這個文件存爲circle.js,並新建一個app.js文件,並寫入如下代碼:

var circle = require('./circle.js'); console.log( 'The area of a circle of radius 4 is ' + circle.area(4));

能夠看到模塊調用也十分方便,只須要require須要調用的文件便可。

 

6.2node模塊的載入及緩存機制
1)載入內置模塊(A Core Module)
2)載入文件模塊(A File Module)
3)載入文件目錄模塊(A Folder Module)
4)載入node_modules裏的模塊
5)自動緩存已載入模塊
1、載入內置模塊
Node的內置模塊被編譯爲二進制形式,引用時直接使用名字而非文件路徑。當第三方的模塊和內置模塊同名時,內置模塊將覆蓋第三方同名模塊。所以命名時須要注意不要和內置模塊同名。如獲取一個http模塊
var  http = require('http')
返回的http便是實現了HTTP功能Node的內置模塊。
2、載入文件模塊絕對路徑的
var   myMod = require('/home/base/my_mod')

 

或相對路徑的
var  myMod = require('./my_mod')
注意,這裏忽略了擴展名「.js」,如下是對等的
varmyMod = require('./my_mod')
varmyMod = require('./my_mod.js')
 
3、載入文件目錄模塊
能夠直接require一個目錄,假設有一個目錄名爲folder,
var  myMod = require('./folder')
 
此時,Node將搜索整個folder目錄,Node會假設folder爲一個包並試圖找到包定義文件package.json。若是folder目錄裏沒有包含package.json文件,Node會假設默認主文件爲index.js,即會加載index.js。若是index.js也不存在,那麼加載將失敗。
假如目錄結構以下
package.json定義以下
 
{
"name": "pack",
"main": "modA.js"
}

 


4、載入node_modules裏的模塊
此時 require('./folder') 將返回模塊modA.js。若是package.json不存在,那麼將返回模塊index.js。若是index.js也不存在,那麼將發生載入異常。
若是模塊名不是路徑,也不是內置模塊,Node將試圖去當前目錄的node_modules文件夾裏搜索。若是當前目錄的node_modules裏沒有找到,Node會從父目錄的node_modules裏搜索,這樣遞歸下去直到根目錄。
沒必要擔憂,npm命令可以讓咱們很方便的去安裝,卸載,更新node_modules目錄。
 
5、自動緩存已載入模塊
對於已加載的模塊Node會緩存下來,而沒必要每次都從新搜索。下面是一個示例
modA.js
console.log('模塊modA開始加載...')
exports = function() {
console.log('Hi')
}
console.log('模塊modA加載完畢')

init.js
命令行執行:
node init.js
varmod1 = require('./modA')
varmod2 = require('./modA')
console.log(mod1 === mod2)
輸入以下
能夠看到雖然require了兩次,但modA.js仍然只執行了一次。mod1和mod2是相同的,即兩個引用都指向了同一個模塊對象。
相關文章
相關標籤/搜索