代理模式
- 为一个对象提供一个代用品或占位符。以便控制对他的访问;
面向对象设计原则-单一职责原则
- 就一个类(对象,函数)而言,应该仅有一个引起他变化的原因;(低耦合)
代理和本体借口的一致性
- 当不需要代理的时候可以替换回本体
保护代理
- 过滤请求;可以用于控制不同权限对象对目标对象的访问
虚拟代理
- 把一些开销很大的对象,延迟到真正需要的时候才创建;
- 实现图片预加载
var myImage = (function() { var imgNode = document.createElement('img'); document.body.appendChild(imgNode); return function(src) { imgNode.src = src; };})();var proxyImage = (function() { var img = new Image; img.onload = function() { myImage(this.src); }; return function(src) { myImage('picture/loading.jpg'); img.src = src; }})();proxyImage('http://tp3.sinaimg.cn/1805666510/180/5718258464/1');
- 实现合并请求
var synchronousFile = function (id) { console.log('开始同步 ' + id);};var proxySynchronousFile = (function() { var cache = [], timer; return function(id) { cache.push(id); if(timer) return; timer = setTimeout(function() { synchronousFile(cache.join(',')); clearTimeout(timer); timer = null; cache.length = 0; }, 2000); //2秒延迟后一次性处理 };})();var checkbox = document.getElementsByTagName('input');for(var i = 0, c; c = checkbox[i++];) { c.onclick = function() { if(this.checked === true) proxySynchronousFile(this.id); }};
在堕性加载中的应用
var miniConsole = (function(){ var cache = []; var handler = function( ev ){ if ( ev.keyCode === 13 ){ //enter var script = document.createElement( 'script' ); script.onload = function(){ for ( var i = 0, fn; fn = cache[ i++ ]; ){ fn(); } }; script.src = 'log.js'; document.getElementsByTagName( 'head' )[0].appendChild(script); document.body.removeEventListener( 'keydown', handler ); } }; document.body.addEventListener( 'keydown', handler, false ); return { log: function(){ var args = arguments; cache.push( function(){ return miniConsole.log.apply( miniConsole, args ); //缓存,当真正加载log.js再执行; }); } }})();miniConsole.log(0);miniConsole.log(1);//按下enter// log.js 代码miniConsole = { log: function(){ // 真正代码略 console.log( Array.prototype.join.call( arguments ) ); }};
缓存代理
- 为一些开销大的运算结果提供暂时的存储
var mult = function () { var a = 1; for(var i = 0, len = arguments.length; i < len; i++) a = a * arguments[i]; return a;};var proxyMult = (function() { var cache = {}; return function() { var args = [].join.call(arguments, ','); if(args in cache) return cache[args] return cache[args] = mult.apply(this, arguments); };})();proxyMult(3,6,8);
- 用于ajax异步请求: 如分页实现时讲数据缓存,下次请求同一页再输出;
利用高阶函数动态创建代理
- 如将上面的
proxyMult
修改,使以后类似计算的缓存代理都用同一个函数产生
var createProxyFactory = function(fn) { var cache = {}; return function() { var args = [].join.call(arguments, ','); if(args in cache) return cache[args]; return cache[args] = fn.apply(this, arguments); }};var proxyMult = createProxyFactory(mult);
其他代理
- 防火墙代理:控制网络资源的访问;
- 远程代理:为一个对象在不同的地址空间提供局部代表;
- 保护代理:用于对象应该有不同访问权限的情况;
- 智能引用代理:取代简单的指针,在访问对象时执行一些附加操作;
写时即复制代理:通常用于复制一个庞大对象的情况;他延迟了复制的过程,当对象真正被修改时才进行复制;
在编写业务代码的时候往往不需要预先设置使用代理模式,当真正发现不方便直接访问某个对象的时候再使用;
迭代器模式
- 顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示的方法;
- 现在流行的大部分语言都有内置的迭代器实现;JS中如
Array.prototype.forEach
内部迭代器
- 内部已经定义好了迭代规则
var each = function (arr, callback) { for(var i = 0, len = arr.length; i < len; i++) callback.call(arr, i, arr[i]); //这里可以修改对象};each([1,2,3], function(index, value) { console.log(this,index,value);});
外部迭代器
- 必须显示地请求迭代下一个元素;增加了复杂度,但也增强累迭代器的灵活性;可以手工控制迭代过程;
var Iterator = function(obj) { var current = 0, len = obj.length; var next = function() { current++; } var isDone = function() { return current >= len; //如果length会自动修改那直接使用 } var getCurrentIten = function() { return obj[current]; } return { next: next, isDone: isDone, getCurrentIten: getCurrentIten }};//一个比较数组相等的例子var compare = function(iterator1, iterator2) { while(!iterator1.isDone() || !iterator2.isDone()) { if(iterator1.getCurrentIten() !== iterator2.getCurrentIten()) throw new Error('不相等'); iterator1.next(); iterator2.next(); } console.log('相等');};compare(Iterator([0,1,2]), Iterator([0,1,2]));
另一个迭代器实现
var Iterator = function (items, container) { var container = container && document.getElementById(container) || document.body, items = container.getElementsByTagName(items), len = items.length, index = 0, splice = [].splice; return { first: function () { index = 0; return items[index]; }, second: function () { index = len - 1; return items[index]; }, pre: function () { if(--index > 0) return items[index]; else { index = 0; return null; } }, next: function () { if(++index < len) return items[index] else { index = len - 1; return null; } }, get: function (num) { index = num >= 0 ? num % len : num % len + len; return items[index]; }, dealEach: function (fn) { var args = splice.call(arguments, 1); for(var i = 0; i < len; i++) { fn.apply(items[i], args); } }, dealItem: function (num, fn) { fn.apply(this.get(num), splice.call(arguments, 2)) }, exclusive: function (num, allFn, numFn) { this.dealEach(allFn); if(Object.prototype.toString.call(num) === '[object Array]') { for(var i = 0, l = num.length; i < l; i++) { this.dealItem(num[i], numFn); } } else { this.dealItem(num, numFn); } } }};var demo = new Iterator('li', 'container');console.log(demo.first());console.log(demo.pre());console.log(demo.next());console.log(demo.get(3));demo.dealEach(function(text, color) { this.innerHTML = text; this.style.background = color;}, 'test', 'pink');demo.exclusive([2,3], function () { this.innerHTML = '被排除的'; this.style.background = 'green';}, function () { this.innerHTML = '被选中的'; this.style.background = 'red';})
迭代类数组和字面量对象
- 实际上只要聚合对象拥有
length
属性并可以下标访问就可以被迭代
应用例子
- 比如一个功能里使用
try-catch,if-else
等根据实际情况尝试不同的执行函数; - 可以将所有要尝试的函数单独分开并设置尝试执行失败返回
false
; - 将所有要尝试的函数通过高迭代器执行,以后增加新的执行函数,只要按照一定顺序迭代就可以;
var iterator = function() { for(var i = 0, fn; fn = arguments[i++];) { var result = fn(); if(result !== false) return result; }};iterator(fn1, fn2, fn3, fn4);
同步变量迭代器
//同步变量var A = { common: {}, client: { user: { username: '', uid: '' } }, server: {}};//同步变量迭代取值器var AGetter = function (key) { if(!A) return; var result = A; key = key.split('.'); for(var i = 0, l = key.length; i < l; i++) { if(result[key[i]] !== undefined) { result = result[key[i]]; } else { return; } } return result;};//同步变量迭代赋值器var ASetter = function (key, val) { if(!A) return; var result = A; key = key.split('.'); for(var i = 0, l = key.length; i < l; i++) { if (result[key[i]] === undefined) { result[key[i]] = {}; } if (!(result[key[i]] instanceof Object)) { throw new Error('A. ' + key.splice(0, i + 1).join('.') + ' is not Object'); return false; } result = result[key[i]]; } return result[key[i]] = val;};console.log(AGetter('client.user.username'));console.log(ASetter('client.server.new', 'on'));