define( ['require'], function( require ){
// ...
} );
or:
define( function( require, exports, module ){
// ...
} );
全局的 require 函數是惟一全局做用域下的變量,像 define同樣。全局的 require 並非規範要求的,可是若是實現全局的 require函數,那麼其須要具備與局部 require 函數 同樣的如下的限定:
1. 模塊標識視爲絕對的,而不是相對的對應另外一個模塊標識。
2. 只有在異步狀況下,require的回調方式才被用來做爲交互操做使用。由於他不可能在同步的狀況下經過 require(String) 從頂層加載模塊。
require(String)
define( function( require ){
var a = require('a'); // 加載模塊a
} );
require(Array, Function)
define( function( require ){
require( ['a', 'b'], function( a,b ){ // 加載模塊a b 使用
// 依賴 a b 模塊的運行代碼
} );
} );
require.toUrl( Url )
define( function( require ){
var temp = require.toUrl('./temp/a.html'); // 加載頁面
} );
RequireJS
RequireJS 是一個前端的模塊化管理的工具庫,遵循AMD規範,它的做者就是AMD規範的創始人 James Burke。因此說RequireJS是對AMD規範的闡述一點也不爲過。
RequireJS 的基本思想爲:經過一個函數來將全部所須要的或者說所依賴的模塊實現裝載進來,而後返回一個新的函數(模塊),咱們全部的關於新模塊的業務代碼都在這個函數內部操做,其內部也可無限制的使用已經加載進來的以來的模塊。
<script data-main='scripts/main' src='scripts/require.js'></script>
那麼scripts下的main.js則是指定的主代碼腳本文件,全部的依賴模塊代碼文件都將從該文件開始異步加載進入執行。
defined用於定義模塊,RequireJS要求每一個模塊均放在獨立的文件之中。按照是否有依賴其餘模塊的狀況分爲獨立模塊和非獨立模塊。
1. 獨立模塊,不依賴其餘模塊。直接定義:
- define({
- method1: function(){},
- method2: function(){}
- });
也等價於
- define(function(){
- return{
- method1: function(){},
- method2: function(){}
- }
- });
2. 非獨立模塊,對其餘模塊有依賴。
- define([ 'module1', 'module2' ], function(m1, m2){
- ...
- });
或者:
- define( function( require ){
- var m1 = require( 'module1' ),
- m2 = require( 'module2' );
- ...
- });
簡單看了一下RequireJS的實現方式,其 require 實現只不過是將 function 字符串而後提取 require 以後的模塊名,將其放入依賴關係之中。
require方法調用模塊
在require進行調用模塊時,其參數與define相似。
- require( ['foo', 'bar'], function( foo, bar ){
- foo.func();
- bar.func();
- } );
在加載 foo 與 bar 兩個模塊以後執行回調函數實現具體過程。
固然還能夠如以前的例子中的,在define定義模塊內部進行require調用模塊
- define( function( require ){
- var m1 = require( 'module1' ),
- m2 = require( 'module2' );
- ...
- });
define 和 require 這兩個定義模塊,調用模塊的方法合稱爲AMD模式,定義模塊清晰,不會污染全局變量,清楚的顯示依賴關係。AMD模式能夠用於瀏覽器環境而且容許非同步加載模塊,也能夠按需動態加載模塊。
CMD 與 seaJS
CMD
在CMD中,一個模塊就是一個文件,格式爲:
define( factory );
全局函數define,用來定義模塊。
參數 factory 能夠是一個函數,也能夠爲對象或者字符串。
當 factory 爲對象、字符串時,表示模塊的接口就是該對象、字符串。
定義JSON數據模塊:
- define({ "foo": "bar" });
經過字符串定義模板模塊:
- define('this is {{data}}.');
factory 爲函數的時候,表示模塊的構造方法,執行構造方法即可以獲得模塊向外提供的接口。
- define( function(require, exports, module) {
- // 模塊代碼
- });
define( id?, deps?, factory );
define也能夠接受兩個以上的參數,字符串id爲模塊標識,數組deps爲模塊依賴:
- define( 'module', ['module1', 'module2'], function( require, exports, module ){
- // 模塊代碼
- } );
其與 AMD 規範用法不一樣。
require 是 factory 的第一個參數。
require( id );
接受模塊標識做爲惟一的參數,用來獲取其餘模塊提供的接口:
- define(function( require, exports ){
- var a = require('./a');
- a.doSomething();
- });
require.async( id, callback? );
require是同步往下執行的,須要的異步加載模塊可使用 require.async 來進行加載:
- define( function(require, exports, module) {
- require.async('.a', function(a){
- a.doSomething();
- });
- });
require.resolve( id )
可使用模塊內部的路徑機制來返回模塊路徑,不會加載模塊。
exports 是 factory 的第二個參數,用來向外提供模塊接口。
- define(function( require, exports ){
- exports.foo = 'bar'; // 向外提供的屬性
- exports.do = function(){}; // 向外提供的方法
- });
固然也可使用 return 直接向外提供接口。
- define(function( require, exports ){
- return{
- foo : 'bar', // 向外提供的屬性
- do : function(){} // 向外提供的方法
- }
- });
也能夠簡化爲直接對象字面量的形式:
- define({
- foo : 'bar', // 向外提供的屬性
- do : function(){} // 向外提供的方法
- });
與nodeJS中同樣須要注意的是,一下方式是錯誤的:
- define(function( require, exports ){
- exports = {
- foo : 'bar', // 向外提供的屬性
- do : function(){} // 向外提供的方法
- }
- });
須要這麼作
- define(function( require, exports, module ){
- module.exports = {
- foo : 'bar', // 向外提供的屬性
- do : function(){} // 向外提供的方法
- }
- });
傳入的對象引用能夠添加屬性,一旦賦值一個新的對象,那麼值錢傳遞進來的對象引用就會失效了。開始之初,exports 是做爲 module.exports 的一個引用存在,一切行爲只有在這個引用上 factory 才得以正常運行,賦值新的對象後就會斷開引用,exports就只是一個新的對象引用,對於factory來講毫無心義,就會出錯。
module 是factory的第三個參數,爲一個對象,上面存儲了一些與當前模塊相關聯的屬性與方法。
module.id 爲模塊的惟一標識。
module.uri 根據模塊系統的路徑解析規則獲得模塊的絕對路徑。
module.dependencies 表示模塊的依賴。
module.exports 當前模塊對外提供的接口。
seaJS
sea.js 核心特徵:
1. 遵循CMD規範,與NodeJS般的書寫模塊代碼。
2. 依賴自動加載,配置清晰簡潔。
兼容 Chrome 3+,Firefox 2+,Safari 3.2+,Opera 10+,IE 5.5+。
seajs.use
用來在頁面中加載一個或者多個模塊
- // 加載一個模塊
- seajs.use('./a');
- // 加載模塊,加載完成時執行回調
- seajs.use('./a',function(a){
- a.doSomething();
- });
- // 加載多個模塊執行回調
- seajs.use(['./a','./b'],function(a , b){
- a.doSomething();
- b.doSomething();
- });
其define 與 require 使用方式基本就是CMD規範中的示例。
AMD 與 CMD 區別到底在哪裏?
看了以上 AMD,requireJS 與 CMD, seaJS的簡單介紹會有點感受模糊,總感受較爲類似。由於像 requireJS 其並非只是純粹的AMD固有思想,其也是有CMD規範的思想,只不過是推薦 AMD規範方式而已, seaJS也是同樣。
下面是玉伯對於 AMD 與 CMD 區別的解釋:
AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
相似的還有 CommonJS Modules/2.0 規範,是 BravoJS 在推廣過程當中對模塊定義的規範化產出還有很多??
這些規範的目的都是爲了 JavaScript 的模塊化開發,特別是在瀏覽器端的。
目前這些規範的實現都能達成瀏覽器端模塊化開發的目的。
區別:
1. 對於依賴的模塊,AMD 是提早執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。CMD 推崇 as lazy as possible.
2. CMD 推崇依賴就近,AMD 推崇依賴前置。看代碼:
- // CMD
- define(function(require, exports, module) {
- var a = require('./a')
- a.doSomething()
- // 此處略去 100 行
- var b = require('./b') // 依賴能夠就近書寫
- b.doSomething()
- // ...
- })
- // AMD 默認推薦的是
- define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好
- a.doSomething()
- // 此處略去 100 行
- b.doSomething()
- // ...
- })
雖然 AMD 也支持 CMD 的寫法,同時還支持將 require 做爲依賴項傳遞,但 RequireJS 的做者默認是最喜歡上面的寫法,也是官方文檔裏默認的模塊定義寫法。
3. AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。
4. 還有一些細節差別,具體看這個規範的定義就好,就很少說了。
總結
本文主要是介紹了一下 AMD CMD的規範,順便簡單的講述了一下 requireJS 與 seaJS。講的較爲籠統,下面的擴展閱讀能夠更好的幫助你理解模塊化以及各個規範。