简单模版模式(SimpleTemplate)
核心
- 定义:通过格式化字符串,拼凑出视图渲染到页面。减少dom操作,优化内存开销,简化代码。
- 重点:封装一个模版生成器,简化模版的创建过程
- 应用:大型框架(如MVC)创建视图操作
示例一:展示模版
- 需求:使用简单模版模式,创建列表视图
- 模版生成器实现
var A = A || {};
A.view = function (name) {
const v = {
};
if (Object.prototype.toString.call(name) === "[object Array]") {
var tpl = "";
for (var i = 0, len = name.length; i < len; i++) {
tpl += arguments.callee(name[i]);
}
return tpl;
}
else {
return v[name] ? v[name] : `<${name}>{#${name}#}</${name}>`;
}
};
console.log(A.view("li"));
console.log(A.view(["h2", "p", "ul"]));
A.formateStr = function (str, data) {
return str.replace(/\{#(\w+)#\}/g, function (match, key) {
return data[key] || "";
});
};
var data = {
lis: [
{
strong: "strong1",
span: "(span1)",
},
{
strong: "strong2",
span: "(span2)",
},
],
};
liTpl = A.formateStr(A.view("li"), {
li: A.view(["strong", "span"]),
});
console.log(liTpl);
const list = data.lis;
let ul = "";
for (var i = 0, len = list.length; i < len; i++) {
if (list[i].em || list[i].span) {
ul += A.formateStr(liTpl, list[i]);
}
}
console.log(ul);
var A = A || {};
A.formateStr = function (str, data) {
return str.replace(/\{#(\w+)#\}/g, function (match, key) {
return data[key] || "";
});
};
A.view = function (name) {
const v = {
};
if (Object.prototype.toString.call(name) === "[object Array]") {
var tpl = "";
for (var i = 0, len = name.length; i < len; i++) {
tpl += arguments.callee(name[i]);
}
return tpl;
}
else {
return v[name] ? v[name] : `<${name}>{#${name}#}</${name}>`;
}
};
A.strategy = {
listPart(data) {
var s = document.createElement("div"),
ul = "",
list = data.data.lis,
tpl = A.view(["h2", "p", "ul"]),
liTpl = A.formateStr(A.view("li"), {
li: A.view(["strong", "span"]),
});
data.id && (s.id = data.id);
for (var i = 0, len = list.length; i < len; i++) {
if (list[i].em || list[i].span) {
ul += A.formateStr(liTpl, list[i]);
}
}
data.data.ul = ul;
s.innerHTML = A.formateStr(tpl, data.data);
document.getElementById(data.containerId).appendChild(s);
},
};
A.init = function (data) {
this.strategy[data.type](data);
};
if (typeof module === "object") {
module.exports = A;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container"></div>
<script src="./index.js"></script>
<script>
A.init({
containerId: "container",
id: "3232",
type: "listPart",
data: {
lis: [
{
strong: "strong1",
span: "(span1)",
},
{
strong: "strong2",
span: "(span2)",
},
],
h2: "h2 text",
p: "p text",
},
});
</script>
</body>
</html>
- 效果
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1b00637c506ee162323c99e72d1b88dd.png)
惰性模式(Layier)
核心
- 定义:减少每次代码执行时的重复性分支判断
- 重点:通过重定义对象,屏蔽分支判断
- 应用:兼容性API的封装
示例一:点击事件的封装
- 需求:封装点击事件,兼容各个浏览器。点击时,屏蔽分支判断
- 加载即执行
A.on = (function (dom, type, fn) {
if (document.addEventListener) {
return function (dom, type, fn) {
dom.addEventListener(type, fn, false);
};
} else if (document.attachEvent) {
return function (dom, type, fn) {
dom.attachEvent("on" + type, fn);
};
} else {
return function (dom, type, fn) {
dom["on" + type] = fn;
};
}
})();
- 惰性执行(第一次调用时,重写A.on方法,并执行)
A.on = function (dom, type, fn) {
if (document.addEventListener) {
A.on = function (dom, type, fn) {
dom.addEventListener(type, fn, false);
};
} else if (document.attachEvent) {
A.on = function (dom, type, fn) {
dom.attachEvent("on" + type, fn);
};
} else {
A.on = function (dom, type, fn) {
dom["on" + type] = fn;
};
}
A.on(dom, type, on);
};
参与者模式(Participator)
核心
- 定义:在特定的作用域中执行给定的函数,并将参数原封不动地传递(bind实现)
- 重点:使用 apply 方法,实现 bind 方法
- 应用:事件绑定,函数柯里化
示例一:函数原型bind方法实现
- 需求:实现 Function.prototype.bind 方法
- js
Function.prototype.bind1 = function (context) {
const that = this;
return function () {
return that.apply(context, arguments);
};
};
var obj = {
a: 1,
b: 2,
};
var f = function () {
console.log(this);
};
f.bind(obj)();
f.bind1(obj)();
示例二:函数柯里化
- 需求:借助柯里化伪造其他函数(多态或重载),根据不同的参数实现不同的功能(类似中间件)
- js
function curry(fn) {
const slice = [].slice;
const args = slice.call(arguments, 1);
return function () {
return fn.apply(null, [...args, ...arguments]);
};
}
function add(a, b) {
return a + b;
}
function addN(n) {
return curry(add, n);
}
var add5 = addN(5);
console.log(add5(9));
示例三:事件绑定
Function.prototype.bind1 = function (context) {
const that = this,
args = [].slice.call(arguments, 1);
return function () {
return that.apply(context, [...args, ...arguments]);
};
};
var callback = function () {
console.log(this, arguments);
};
var data1 = {
text: "第一组数据",
};
var data2 = {
text: "第二组数据",
};
var btn = document.getElementsByTagName("button")[0];
var btnFn = callback.bind(btn, data2, data1);
btn.addEventListener("click", btnFn);
var p = document.getElementsByTagName("p")[0];
var pFn = callback.bind1(p, data1, data2);
p.addEventListener("click", pFn);
setTimeout(() => {
p.removeEventListener("click", pFn);
}, 5000);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>111</button>
<p>222</p>
<script src="./index3.js"></script>
</body>
</html>
- 效果
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e4668ea2a5c636c432d7dad7fde6fcdc.png)
示例四:反柯里化函数
Function.prototype.uncurry = function () {
const that = this;
return function () {
console.log(that, arguments);
return Function.prototype.call.apply(that, arguments);
};
};
var toString = Object.prototype.toString.uncurry();
console.log(toString(() => {}));
console.log(toString(null));
var push = [].push.uncurry();
var obj = {};
push(obj, "第一个", "第二个");
console.log(obj);
Function.prototype.call;
Function.prototype.call.call(Math.max, 1, 3, 4);
Function.prototype.call.apply(Math.max, [1, 3, 4]);
等待者模式(Waiter)
核心
- 定义:监听多个异步任务,触发未来发生的动作
- 重点:需等待多个异步任务全部完成时,执行后续操作
- 应用:接口拆分
示例一:模拟并发请求,集中处理其结果
- 需求:多个异步或同步任务,全部成功后调用成功回调
- 原理:某个异步任务完成后,判断是否所有的异步任务均已完成(类似于轮循)
var Waiter = function () {
var dfd = [],
doneArr = [],
failArr = [],
slice = [].slice,
that = this;
this.Deferred = function () {
return new Promise();
};
this.when = function () {
dfd = slice.call(arguments);
for (var i = dfd.length - 1; i >= 0; i--) {
if (
!dfd[i] ||
dfd[i].status !== "pending" ||
!dfd[i] instanceof Promise
) {
dfd.splice(i, 1);
}
}
return that;
};
this.done = function () {
doneArr = [...doneArr, ...arguments];
return that;
};
this.fail = function () {
failArr = [...failArr, ...arguments];
return that;
};
var Promise = function () {
this.status = "pending";
};
Promise.prototype = {
resolve() {
this.status = "resolved";
if (!dfd.length) return;
for (let i = dfd.length - 1; i >= 0; i--) {
if (dfd[i] && dfd[i].status !== "resolved") {
return;
}
dfd.splice(i, 1);
}
_exec(doneArr);
},
reject() {
this.status = "rejected";
if (!dfd.length) return;
dfd = [];
_exec(failArr);
},
};
function _exec(arr) {
let i = 0,
len = arr.length;
for (; i < len; i++) {
try {
arr[i] && arr[i]();
} catch (e) {}
}
}
};
var waiter = new Waiter();
var zero = (function () {
const p = waiter.Deferred();
p.resolve();
return p;
})();
zero.data = 0;
var first = (function () {
const p = waiter.Deferred();
setTimeout(function () {
console.log("first done");
first.data = 1;
p.resolve();
}, 1000);
return p;
})();
var second = (function () {
const p = waiter.Deferred();
setTimeout(function () {
console.log("second done");
second.data = 2;
p.resolve();
}, 2000);
return p;
})();
var third = (function () {
const p = waiter.Deferred();
p.resolve();
return p;
})();
third.data = 3;
var four = (function () {
const p = waiter.Deferred();
setTimeout(function () {
console.log("four fail");
four.data = 2;
p.reject();
}, 2000);
return p;
})();
waiter
.when(zero, first, second, third)
.done(function () {
console.log("success", zero, first, second, third);
})
.fail(function () {
console.log("fail", zero, first, second, third);
});