blogs
blogs copied to clipboard
常见的几种设计模式
单例模式
singleton,产生一个类的唯一实例。 可以减少全局变量,且保证该实例的唯一性。 但会有闭包的毛病(占用内存),再者想创建另一个相似实例有悖于此模式。
var singleton = function( fn ){
var result;
return function(){
return result || ( result = fn .apply( this, arguments ) );
}
}
// 伪代码,不管运行几次 createGame,都只有一个 Game 实例
var createGame = singleton(function() {
return new Game();
})
// 或者这样,只会新建一个元素
var num = 0;
var createMask = singleton(function(){
var $d = document.createElement('div');
$d.className = 'x' + ++num;
return document.body.appendChild($d);
});
var mask1 = createMask();
var mask2 = createMask();
console.log(mask1, mask2); // <div class="x1"></div> <div class="x1"></div>
观察者模式
即 on 绑定回调,trigger 触发回调
var Events = function() {
var listen, log, obj, one, remove, trigger, __this;
var obj = {}, __this = this;
listen = function( key, eventfn ) {
var stack, _ref;
stack = ( _ref = obj[key] ) != null ? _ref : obj[ key ] = [];
return stack.push( eventfn );
};
one = function( key, eventfn ) {
remove( key );
return listen( key, eventfn );
};
remove = function( key ) {
var _ref;
return ( _ref = obj[key] ) != null ? _ref.length = 0 : void 0;
};
trigger = function() { //面试官打电话通知面试者
var fn, stack, _i, _len, _ref, key;
key = Array.prototype.shift.call( arguments );
stack = ( _ref = obj[ key ] ) != null ? _ref : obj[ key ] = [];
for ( _i = 0, _len = stack.length; _i < _len; _i++ ) {
fn = stack[ _i ];
if ( fn.apply( __this, arguments ) === false)
return false;
}
}
return {
on: listen,
one: one,
remove: remove,
trigger: trigger
}
}
// 例子
var eee = new Events;
eee.on('end', function(){ console.log('2s 后') });
setTimeout(function(){ eee.trigger('end'); }, 2000);
适配器模式
adapter,类似于USB转接口,也就是中间加一个过程,让参数得以匹配
// 例子1:改变函数参数传递
var something = { x: 1, y: 2, z: 3 };
var myfun = function(a, b, c) {
console.log(a, b, c);
}
var _myfun = function(obj) { // 这就是适配器
obj.x = Math.max(0, Math.min(obj.x, 5));
myfun(obj.x, obj.y, obj.z);
}
console.log(_myfun(something));
代理模式
proxy,把对一个对象的访问, 交给另一个代理对象来操作。 比如进行允许/拒绝/缓存/合并等操作。
// 例子
var plus = function () {
var args = [].slice.call(arguments, 0);
return args.reduce((x, y) => x + y);
}
var proxy = function (fn) {
var cache = {};
return function(){
var args = Array.prototype.join.call(arguments, "-");
if( args in cache ){ // 判断是否被计算过
console.log( "从缓存中拿取" );
return cache[args];
}
return cache[args] = fn.apply(null, arguments);
}
}
var add = proxy(plus);
console.log(add(1, 2, 3, 4)); // 10
console.log(add(1, 2, 3, 4)); // 从缓存中拿取 10
//
包装/装饰者模式
decorator,为对象动态加入行为,都是不改变原来的对象添加功能。 包装模式与代理模式的不同,在于代理模式返回的结果会不变,包装模式则可能不会。
委托模式
delegater,接收多个对象,将请求委托给另一个对象统一处理请求。
// 比如,事件冒泡和事件委托
function clicked() {}
var $li = document.querySelecterAll('li');
for (var i=0,len=$li.length; i<len; i++) {
$li.onclick = clicked
}
var $ul = document.querySelecterAll('ul');
$ul.onclick = function(e){
var el = e.target;
if (el.tagName.toLowerCase() == 'li') {
clicked.call(el, e)
}
}