同步模块模式
·
Yin灏
/**
* 模块化:将复杂的系统分解成高内聚、低耦合的模块,是系统开发变得可控、可维护、可扩展,提高模块的复用率。
* 同步模块模式:请求发出后,无论模块是否存在,立即执行后续的逻辑,实现模块开发中的对象模块的立即引用。
*/
// 模块管理器与创建方法
// 定义模块管理器单体对象
/**
* 首先定义一个模块管理器对象 F,然后为其创建一个模块定义方法 define
*/
var F = F || {};
/**
* @param {*} str 模块路由
* @param {*} fn 模块方法
*/
F.define = function (str, fn) {
// 解析模块路由
var parts = str.split("."),
// old 当前模块的祖父模块,parent 当前模块父模块
// 如果在闭包中,为了屏蔽对模块的直接访问,建议将模块添加给闭包内部私有变量
old = (parent = this),
// i 模块层级,len 模块层级长度
i = (len = 0);
// 如果第一个模式是模块管理器单体对象,则移除
if (parts[0] === "F") {
parts = parts.slice(1); // 删除数组第一个元素
}
// 屏蔽对 define 与 module 模块方法的重写
if (parts[0] === "define" || parts[0] === "module") {
return;
}
// 遍历路由模块并定义每层模块
for (len = parts.length; i < len; i++) {
// 如果父模块中不存在当前模块
if (typeof parent[parts[i]] === "undefined") {
// 声明当前模块
parent[parts[i]] = {};
}
// 缓存下一层级的祖父模块
old = parent;
// 缓存下一层级父模块
parent = parent[parts[i]];
}
// 如果给定模块方法则定义该模块方法
if (fn) {
// 此时 i 等于 parts.length , 故减一
old[parts[--i]] = fn();
}
// 返回模块管理器单体对象
return this;
};
/**
* 创建模块
* 创建 String 模块,对于 String 模块,要为我们提供 trim 方法
*/
// F.string 模块
F.define("string", function () {
// 接口方法
return {
// 清楚字符串两边空白
trim: function (str) {
return str.replace(/^\s+|\s+$/g, "");
},
};
});
// 不允许如下直接使用
//console.log(F.string.trim(' 测试用例 ')); // '测试用例'
F.define("dom", function () {
var $ = function (id) {
$.dom = document.getElementById(id);
return $;
};
$.html = function (html) {
if (html) {
this.dom.innerHTML = html;
return this;
} else {
return this.dom.innerHTML;
}
};
return $;
});
// 测试用例
console.log(F.dom("demo").html()); // 'demo'
/**
* 对于模块的创建,我们也可以先声明后创建,如添加 addClass() 为元素添加 class 方法
*/
// 为模块 dom 添加 addClass 方法
F.define("dom.addClass");
F.dom.addClass = (function (type, fn) {
return function (className) {
// 如果不存在该类
if (!~this.dom.className.indexOf(className)) {
// 简单添加类
this.dom.className += " " + className;
}
};
})();
// 测试用例
F.dom("demo").addClass("demo");
/**
* 模块调用方法
* 要使用方法,需要创建一个 ‘使用’ 模块方法 - module
*/
F.module = function () {
// 将参数转化为数组
var args = [].slice.call(arguments),
// 获取回调执行函数
fn = args.pop(),
// 获取依赖模块,如果 args[0] 是数组,则依赖模块为 args[0],否则依赖模块为 arg
parts = args[0] && args[0] instanceof Array ? args[0] : args,
// 依赖模块列表
modules = [],
// 模块路由
modIDs = "",
// 依赖模块索引
i = 0,
// 依赖模块长度
ilen = parts.length,
// 父模块,模块路由层级索引,模块路由层级长度
parent,
j,
jlen;
// 遍历依赖模块
while (i < ilen) {
// 如果是模块路由
if (typeof parts[i] === "string") {
// 设置当前模块父对象(F)
parent = this;
// 解析模块路由,并屏蔽掉模块父对象
modIDs = parts[i].replace(/^F\./, "").split(".");
// 遍历模块路由层级
for (j = 0, jlen = modIDs.length; j < jlen; j++) {
// 重置父模块
parent = parent[modIDs[j]] || false;
}
// 将模块添加到依赖模块列表中
modules.push(parent);
} else {
// 如果是模块对象
// 直接加入依赖模块列表中
modules.push(parts[i]);
}
// 取下一个依赖模块
i++;
}
// 执行回调执行函数
fn.apply(null, modules);
};
// 调用模块
// 引用 dom 模块与 document 对象
F.module(["dom", document], function (dom, doc) {
dom("demo").html("new add!");
doc.body.style.background = "blue";
});
// 依赖引用 dom 模块, string.trim 方法
F.module("dom", "string.trim", function (dom, trim) {
var html = dom("demo").html();
var str = trim(html);
console.log(str);
});