Skip to content

Instantly share code, notes, and snippets.

@dexteryy
Created September 10, 2012 08:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dexteryy/3689700 to your computer and use it in GitHub Desktop.
Save dexteryy/3689700 to your computer and use it in GitHub Desktop.
AMD -> module pattern
// 这个define的实现会让amd模块声明变成传统的module pattern
function define(fullname, deps, block){
if (!block) {
if (deps) {
block = deps;
} else {
block = fullname;
fullname = [];
}
if (typeof fullname !== 'string') {
deps = fullname;
fullname = "";
} else {
deps = [];
}
}
var callee = define,
len = deps.length,
exports = {},
opt = callee._global_exports[fullname] || {},
current_ns = callee._current_ns = opt.ns
|| callee._current_ns || callee._ns || 'window';
deps = ((/^function.*?\(([\w'"\/\-\:,\n\r\s]*)\)/
.exec(block.toString()) || [])[1] || '')
.replace(/\s+/g, '').split(',');
deps.length = len;
var args = deps.map(function(name){
return (window[current_ns] || {})[name];
});
args.push(function(reqs, callback){
if (callback) {
require(reqs, callback);
} else {
return (callee._global_exports[reqs] || {}).exports;
}
});
args.push(exports);
exports = opt.exports = block.apply(this, args) || exports;
if (opt.names) {
opt.names.forEach(function(name){
name = name.split('.');
var context = window, i = name[0];
if (name[1]) {
context = context[i] = context[i] || {};
i = name[1];
}
context[i] = exports;
});
}
callee._current_ns = null;
}
// require的实现跟define一样,不过是异步的
function require(reqs){
if (typeof reqs === 'string') {
reqs = [reqs];
}
var args = arguments;
setTimeout(function(){
define.apply(this, args);
}, 0);
}
define._global_exports = {};
// 为模块设置命名空间,既可以避免产生全局变量,
// 也可以隔离不同体系的模块(比如'mod/event'和'jquery/event'),避免命名冲突
define.ns = function(mid, namespace){
if (!namespace) {
this._ns = mid;
} else {
var opt = this._global_exports;
if (!opt[mid]) {
opt[mid] = {
names: []
};
}
opt[mid].ns = namespace;
}
};
// 将模块的exports映射到全局命名空间下,让没有封装到amd模块里的代码也可以使用
define.config = function(mid, vars){
if (typeof mid === 'object') {
for (var i in mid) {
this.config(i, mid[i]);
}
return;
}
var opt = this._global_exports;
if (!opt[mid]) {
opt[mid] = {
ns: this._ns,
names: []
};
}
if (typeof vars === 'string') {
vars = [vars];
}
[].push.apply(opt[mid].names, vars);
};
// 以下是DEMO
// 自定义默认命名空间,默认为window
define.ns('Ark');
// 给模块单独定义命名空间,这个模块依赖的参数都会从这个命名空间下读取
define.ns('B', 'Y');
// 手工配置模块的exports在全局命名空间下的名称(一对多)
define.config('mod/dialog', '$.dialog');
define.config('mod/dialog', ['Ark.dui_dialog', 'Ark.Dialog']);
define.config({
'mod/lang': ['_', 'Ark._'],
'A': ['Ark.A', 'Y.A'],
'B': ['Ark.B', 'Y.B']
});
// 合并进来的 mod/lang.js,如果之前没有模块名,可在合并脚本执行的时候自动生成
// 要用现成工具的话,可以先用ozma.js把所有amd模块合并为一个发布文件,再把这个发布文件用 @import 的方式合并到传统网页的js中
define('mod/lang', function(require, exports){
exports.isFunction = function(){};
});
// 合并进来的 mod/dialog.js
define('mod/dialog', ['mod/lang'], function(_, require, exports){
console.info('mod/dialog running..');
require('A', function(A){
// 因为这里的require在模块内调用,所以这个函数会异步执行,参数A从mod/dialog的命名空间下读取(Ark.A)
console.info('require A: ', A);
});
return function(str){
// 只有一个参数的require会立刻执行,返回模块B的exports,不需要全局命名空间
console.info(str, _, require('B'));
};
});
define('A', function(){
return { name: 'A' };
});
// 因为模块B的命名空间是Y,所以这里的参数A取的是Y.A
define('B', ['A'], function(A){
return { name: 'B', A: A };
});
Ark.dui_dialog('Dialog: ');
console.info('lang: ', _);
console.info('Ark: ', Ark);
console.info('Y: ', Y);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment