[JavaScript] 模組化規範 - CommonJS, AMD, CMD
常見的作法... 我們把頁面當作一個一個的模組,借用 jQuery 或是原生的 dom library 進行初始化jQuery(function{
// init here
});
//or
document.ready(function(){
// init here
});
至於功能模組化或是函式庫重用很少在我們的系統中出現(根據本人不專業觀察)
一方面是業務邏輯等級的設計是真的很困難的,應該只有非常有經驗(重做很多次)的人有辦法處理
指的"絕對"不是只很會寫程式的人,而是很懂 Domain 而且會架構的人
因為分析階段完成後,並沒有有效的銜接設計階段方法,來確切地設計出有彈性地模組
這個情況並不是因為偷懶不進行設計
而是設計完不容易應付修改,尤其只能保證需求一定會改變...
不容易調整的設計,成為殺死團隊的第一把刀
一方面如果系統不是產品,只是一次開發進入維護階段的系統,其實靠人力跟運氣來處理就可以
誰敢重構已經能用的東西,一定是立馬被鞭 (想像是美麗的、現實是殘酷的)
所以這種設計一般發生在共用的字串處理、連線處理、非常常用的業務邏輯元件上
設計到業務邏輯等級,感覺還是在維護階段,針對常修改的功能進行來的合理些
再一方面在台(ㄍㄨㄟˇ)灣(ㄉㄠˇ)了解業務邏輯 、懂設計又那麼閒的工程師,應該蠻快就變成管理職...
(抱怨文完畢,正文開始)
------
CommonJS (http://www.commonjs.org/) 訂定了在非瀏覽器上面的許多 JavaScript 規範,其中正包括模組 (Modules) 。
而在瀏覽器裡面,使用 AMD 模式來處理,這邊主要參考 RequireJS (http://requirejs.org/docs/whyamd.html) 與 AmdJS (https://github.com/amdjs/amdjs-api/blob/master/AMD.md)
CommonJS - Modules/1.0 (http://wiki.commonjs.org/wiki/Modules/1.0)
基本上是這樣,完整點可以直接看定義,另外 1.1 與 1.1.1 版本看起來有再擴充,適用情境也更完整。模組:使用 exports 變數承接定模組,一般使用檔案名稱當作模組 id
引用:使用 require 函數來指定引用的模組 id
math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
increment.jsvar add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
program.jsvar inc = require('increment').increment;
var a = 1;
inc(a); // 2
AMD - Asynchronous Module Definition
Module//Calling define with a dependency array and a factory function
define(['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
Named Module//Calling define with module ID, dependency array, and factory function
define('myModule', ['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
Sugar1define([ "require", "jquery", "blade/object", "blade/fn", "rdapi",
"oauth", "blade/jig", "blade/url", "dispatch", "accounts",
"storage", "services", "widgets/AccountPanel", "widgets/TabButton",
"widgets/AddAccount", "less", "osTheme", "jquery-ui-1.8.7.min",
"jquery.textOverflow"],
function (require, $, object, fn, rdapi,
oauth, jig, url, dispatch, accounts,
storage, services, AccountPanel, TabButton,
AddAccount, less, osTheme) {
});
Sugar2 Mixingdefine(function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
當不是都透過 define 撰寫,還可以使用 requirejs.config() 來更有彈性的設定模組與模組間的 dependencyrequirejs.config({
//Remember: only use shim config for non-AMD scripts,
//scripts that do not already call define(). The shim
//config will not work correctly if used on AMD scripts,
//in particular, the exports and init config will not
//be triggered, and the deps config will be confusing
//for those cases.
shim: {
'backbone': {
//These script dependencies should be loaded before loading
//backbone.js
deps: ['underscore', 'jquery'],
//Once loaded, use the global 'Backbone' as the
//module value.
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'foo': {
deps: ['bar'],
exports: 'Foo',
init: function (bar) {
//Using a function allows you to call noConflict for
//libraries that support it, and do other cleanup.
//However, plugins for those libraries may still want
//a global. "this" for the function will be the global
//object. The dependencies will be passed in as
//function arguments. If this function returns a value,
//then that value is used as the module export value
//instead of the object found via the 'exports' string.
//Note: jQuery registers as an AMD module via define(),
//so this will not work for jQuery. See notes section
//below for an approach for jQuery.
return this.Foo.noConflict();
}
}
}
});
//Then, later in a separate file, call it 'MyModel.js', a module is
//defined, specifying 'backbone' as a dependency. RequireJS will use
//the shim config to properly load 'backbone' and give a local
//reference to this module. The global Backbone will still exist on
//the page too.
define(['backbone'], function (Backbone) {
return Backbone.Model.extend({});
});
CMD - Common Module Definition(https://github.com/cmdjs/specification/blob/master/draft/module.md)
math.jsdefine(function(require, exports, module) {
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
});
increment.jsdefine(function(require, exports, module) {
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
});
program.jsdefine(function(require, exports, module) {
var inc = require('increment').increment;
var a = 1;
inc(a); // 2
module.id == "program";
});
UMD - Universal Module Definition
只是收攏上面那些定義不過相對彈性也較差(function (root, factory) {
if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('b'));
} else if (typeof define === 'function' && define.amd) {
// AMD
define(['b'], function (b) {
return (root.returnExportsGlobal = factory(b));
});
} else {
// Global Variables
root.returnExportsGlobal = factory(root.b);
}
}(this, function (b) {
// Your actual module
return {};
}));
沒有留言:
張貼留言