代理模式
定义:为一个对象提供一个代用品和占位符,以便控制对它的访问
常用的虚拟代理模式:某个花销很大的操作,可以通过虚拟代理的方式延迟到需要创建的时候才去创建 (函数的节流防抖也是一种代理模式)
例如:使用虚拟代理实现图片的懒加载
图片的懒加载的方式:先通过一张 loading 图占位符,然后通过异步的方式加载图片,等待图片加载好,再把加载好的图片放到标签里面
var myImage = (function () {
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: function (src) {
imgNode.src = src;
},
};
})();
var proxyImage = (function () {
var img = new Image();
img.onload = function () {
myImage.setSrc(img.src);
};
return {
setSrc: function (src) {
img.src = src; // 当图片加载完成时会触发 上面的img.onload 然后替换掉图片
myImage.setSrc("loading图片地址");
},
};
})();
proxyImage.setSrc("图片地址");
代理的意义是什么:单一职责原则(一个对象只有一个职责,如果一个对象担任过多的职责,那么这个对象将会不可控,代码就会变的很脆弱 )
再看一个例子:虚拟代理合并 HTTP(取自 js 设计模式与开发实践)
<body>
<div id="wrapper">
<input type="checkbox" id="1"></input>1
<input type="checkbox" id="2"></input>2
<input type="checkbox" id="3"></input>3
<input type="checkbox" id="4"></input>4
<input type="checkbox" id="5"></input>5
<input type="checkbox" id="6"></input>6
<input type="checkbox" id="7"></input>7
<input type="checkbox" id="8"></input>8
<input type="checkbox" id="9"></input>9
</div>
</body>
<script type="text/javascript">
// 模拟http请求
var synchronousFile = function (id) {
console.log('开始同步文件,id 为: ' + id);
};
var inputs = document.getElementsByTagName('input')
var wrapper = document.getElementById('wrapper')
wrapper.onclick = function (e) {
if (e.target.tagName === 'INPUT' && e.target.checked) {
proxySynchronousFile(e.target.id)
}
}
var proxySynchronousFile = (function () {
var cacheIds = [], // 缓存id
timeId = 0 //定时器
return function (id) {
if (cacheIds.indexOf(id) < 0) {
cacheIds.push(id)
}
clearTimeout(timeId)
timeId = setTimeout(() => {
synchronousFile(cacheIds.join(',')) //调用函数
cacheIds = []
}, 1000)
}
})()
</script>
通过代理缓存要发送的请求,最后统一发送请求
实际上上面的函数就是一个函数防抖(所以说防抖节流也是一种代理模式)
看过这几种模式是不是觉得设计模式也并不是很难懂的东西,但是如何使用设计模式,什么地方该用什么样的设计模式是需要一定的积累和应用的
一种大家几乎都使用过的代理模式:事件代理
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
</script>
因为存在太多的 li,不可能每个都去绑定事件。这时候可以通过给父节点绑定一个事件,让父节点作为代理去拿到真实点击的节点。
网友评论