代理模式
前言
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。 例如:
下面就介绍最常用的几种场景
保护代理
例如作为孩子我们总希望他健康成长,在成长路上遇到的烦恼会被家长解决,这样来看其实就是保护代理,下面用一段伪代码来实现。
function Children() {
this.knowledge = [];
}
Children.prototype.Study = function(content) {
// ...学习,增加知识
this.knowledge.push(content);
};
var Parent = (function() {
var small = new Children();
return {
knowledge: function(content) {
if (content === "bad") {
// 坏的,过滤掉
} else {
small.Study(content);
}
}
};
})();
上面用伪代码的形式来实现了一个保护例子,不过你可能会困惑,这样不是多此一举么,我们完全可以在Children
内部实现,不过这样做
- 增加了程序耦合度,如果想要过滤更多,或者某一天不过滤了,还要更改代码
- 违背了单一原则,对于代码的阅读和维护,造成了更多的成本
缓存代理
缓存代理是很实用的一个例子,例如一个阶乘函数
,计算 n 的阶乘,最多需要保存 n 个调用记录,我们可能这样写
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5); // 120
不过如果重复计算 5 或者 10,很明显造成了多次浪费,这个时候就可以使用代理,把结果缓存下来,如果存在就直接返回。
function next(n, total) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
var factorial = (function() {
var obj = {};
return function(v) {
if (obj[v]) {
return obj[v];
}
obj[v] = next(v);
return obj[v];
};
})();
factorial(5); // 120
factorial(5); // 120
上面就将结果缓存了下来,除此之外还可以引用在异步请求中可以节省加载的时间。
应用场景
上面简单介绍了两种模式,实际上还有很多,比如虚拟代理、远程代理、防火墙代理等,不过这里不做介绍了,下面看看使用场景。
jquery
jquery
基于链式调用,比如$('.a').html('').text('')
,不过你会不会很好奇,$()
调用的时候它是怎么记录这个值的呢,每次调用$()
存储的 dom 都不相同,实际上它就是借用了代理模式,这里直接贴代码了
function Jquery(dom) {
this.dom = dom;
}
// 代理者
function $(dom) {
return new Jquery(dom);
}
$.prototype = Jquery.prototype = {
// 只做演示,不涉及具体代码
html() {
return this;
},
text() {
return this;
}
};
$(".a")
.html("")
.text("");
vue
我们在使用 vue 的时候给定了配置项data
,它是一个对象,里面的属性会被 vue 响应式处理,我们可以通过this.
的方式来简单访问,也是用了代理模式,下面就用一段伪 vue 代码来说明
class Mvvm {
constructor(option = {}) {
this.$option = option;
this._data = option.data || {};
// 代理数据
for (const name in this._data) {
Object.defineProperty(this, name, {
configurable: true,
enumerable: true,
get() {
return this._data[name];
},
set(v) {
return (this._data[name] = v);
}
});
}
}
}
export default Mvvm;
可以复制上面代码,自己简单试下。