子產品化程式設計是javascript語言的一個特性,其實不光javascript語言有子產品化思想,java9也支援子產品化,是以說子產品化是一種程式設計的趨勢,也是一種新的解決方案。子產品化程式設計将我們以前單獨編寫的元件或者工具等等通過某種方式變為了一種可以很友善調用的代碼。在子產品化程式設計之前,我們編寫的元件或者工具都是零散的,有些元件依賴另一個元件,當他們加載的時候,需要嚴格指定先後順序,否則出現報錯。
子產品化程式設計通過定義子產品,辨別子產品,引用子產品的方式解決了元件依賴之間的關系。子產品化程式設計主要由commonjs,cmd,amd等規範組成,nodejs實作了commonjs規範,seajs實作了cmd規範,requirejs實作了amd規範。
這裡需要說明的是cmd是common module define即通用子產品定義規範的簡稱,而amd是asynchronous module define即異步子產品定義的規範簡稱。他們之間孰優孰劣曾經在網上有很精彩的辯論,玉帛似乎更堅持cmd規範優于amd規範,畢竟seajs是他創作的。
nodejs實作commonjs規範,應用在服務端,seajs和requirejs分别實作了cmd規範和amd規範,應用在浏覽器端,但是也不是絕對的,seajs和requirejs都提供了nodejs的npm子產品,可以通過npm install seajs或者npm install requirejs的方式安裝seajs和requirejs,并且可以讓seajs和requirejs在服務端使用。
先來看看nodejs實作commonjs規範的文法以及調用示例。我們通過 兩個檔案來示範他們的用法和差別math.js定義一個add函數,計算兩個數字之和,main.js是調用math子產品的js。一般需要通過exports或者module.exports對外暴露子產品,如下所示:
math.js
function add(a,b){
return a+b;
}
module.exports = {add:add}
main.js
var math = require("./math");
console.log("math.add(1,2)="+math.add(1,2));
運作node main.js,列印資訊如下:

這裡module.exports對外暴露子產品,其實可以通過exports = {add:add}也是一樣的效果,或者exports.add = function(a,b){return a+b;}也是可以的,最簡單的就是利用lambda表達式了:
math.js
exports.add = (a,b)=>a+b
main.js
var math = require("./math");
console.log("math.add(1,2)="+math.add(1,2));
運作,列印結果如下:
以上兩種方式都是exports={}或者exports.xxx = yyy,對外暴露的是一個json對象,我們通路的時候直接通過require引入子產品,然後調用子產品中的對應暴露的方法或者變量。還有一種簡單的暴露方式,就是以匿名函數的形式暴露,如下所示:
math.js
module.exports = (a,b) => a+b;
main.js
var add = require("./math");
console.log("add(1,2)="+add(1,2));
這種方式暴露的時候,隻是暴露一個匿名函數,當我們引用這個子產品的時候,其實就是指定的函數,調用的時候,直接通過module()就可以調用了。而不能使用module.func()的方式。運作結果如下所示:
值得一說的是,當我們使用typescript語言編寫es6子產品化,然後通過tsc --module commonjs 編譯出來的js子產品化是通過閉包的形式來編寫相應的函數,以及函數的方法,最後暴露函數,這個時候,我們調用子產品,需要new Function(),然後進行對象的方法調用,如下所示:
Math.ts
export class Math{
public add(a:number,b:number){
return a + b;
}
}
運作tsc -m commonjs Math.js
當我們在main.js中調用add方法的時候,需要引入Math子產品,然後new module.Math().add(1,2)的方式調用,如下所示:
main.js
var math = require("./Math");
console.log("Math.add(1,2)="+new math.Math().add(1,2));
運作截圖:
以上都是介紹nodejs作為實作了commonjs規範的子產品化程式設計的一些思路和實戰,有很多有意思的地方。下面我們來看實作了amd規範的requirejs的使用。
requirejs一般用在浏覽器中,但是npm也提供了requirejs的安裝依賴,可以通過npm i requirejs的方式安裝,其實requirejs也可以作為子產品化在nodejs中使用,隻不過需要做一些設定,下面給出一個可以通過nodejs來運作的requirejs示例。
我們還是以math.js,main.js為例,math.js提供一個add(a,b)函數 ,然後main.js在代碼中引入math依賴子產品,然後調用add()函數,列印結果,我們重點關注requirejs作為實作了amd規範的文法特征,這裡引入關鍵字define,我們通過define來定義子產品,在define函數體中,通過return的方式暴露子產品。
math.js
define(function(){
var add = function(a,b){
return a+b;
};
return {
add:add
}
});
main.js
var requirejs = require("requirejs");
requirejs.config({
nodeRequire:require
});
requirejs(["math"],function(math){
console.log("math.add(1,2)="+math.add(1,2));
});
在main.js中相對複雜一點,因為我們不能像以前commonjs規範那樣,直接require就可以使用了,我們需要設定requirejs,然後通過requirejs([module],function(module){ module.func() ;})的形式來調用。其中requirejs.config({nodeRequire:require})這一步是可選的,運作node main.js,結果如下:
最後來看看實作了cmd規範的子產品化架構seajs的使用,seajs和requirejs一樣,都是使用在浏覽器端的,但是npm同樣提供了安裝依賴,可以通過npm i seajs的方式安裝,而且同樣的,我們可以通過在nodejs服務端使用seajs,也是需要和requirejs一樣稍作配置,我們先來看看seajs子產品化書寫方式。
math.js
define(function(require,exports){
exports.add = function(a,b){
return a + b;
}
})
main.js
require("seajs");
var math = require("./math");
console.log("math.add(1,2)="+math.add(1,2));
在nodejs環境中使用seajs子產品化,需要在使用的時候引入seajs,然後就和普通的子產品一樣使用了,運作node main.js,列印資訊如下:
以上通過一些執行個體,簡單介紹了一下commonjs,cmd,amd作為子產品化程式設計規範的差別,以及實作了他們各自規範的具體架構,其中nodejs使用在服務端,requirejs和seajs主要使用在浏覽器端。