装饰者模式
1.jquery $('.a').find('.b') , $('.a') 以后返回一个对象, find('.b') 以后 也是返回一个对象,对$('.a')装饰一个方法 find , $('.a').find('.b') 再加一个装饰 width(); 返回的仍然是一个完整的jquery的对象
这就是装饰者模式。
参考书:[JavaScript模式].Stoyan.Stefanov =》第153页
所以可以初步理解为,一个对象,有很多方法,每次调用以后,任然返回一个完整的值被方法装饰过的对象。能实现这样的功能,就是装饰者模式。所以可以自己来实现一下。
假设,有个对象 obj,修改它的长度为100,obj.changeLength(100), 再次计算它的平方根号
为100*100. obj.changeLength(100).Math("sqr")或者 100+100 obj.changeLength(100).Math("add") ,(100+100)*(100 + 100)
obj.changeLength(100).Math("add").Math('sqr') 返回结果。
那么每次调用之后,返回的都是一个对象,要如何实现,这个对象的构造方法?
function setObj(width){ this.width = 100||width; } setObj.prototype.setWidth = function(){ return this.width + 'px'; } setObj.prototype.changeLength = function(width){ this.width = width; return this; } setObj.prototype.Math = function(value){ if(value == 'add'){ this.width = this.width + this.width; }else if(value == 'sqr'){ this.width = this.width * this.width; } return this; } var newobj = new setObj(120); console.log(newobj.changeLength(200).Math("add").Math("sqr").setWidth());
console.log(newobj.changeLength(200).Math("add").setWidth());
打印的 160000px 这样就能实现了,这样随便调用什么方法,都是返回的一个完整的对象。
但是这样写有个问题,就是Math("add")方法实际框架中,可能会包含很多计算,修改很多值,所以嵌套在if里面无法维护。修改
setObj.prototype.Math 不返回 this, 返回一个对 setObj 的继承,和方法的重写。不去改变初始参数this.width的值。
function setObj(width){ this.width = width||100; } setObj.prototype.getWidth = function(){ return this.width; } setObj.prototype.changeLength = function(width){ this.width = width; return this; } setObj.Maths = {}; setObj.Maths.add = { getWidth: function() { console.log(this); return this.getWidth()+'%'; } } setObj.Maths.sqr = { getWidth: function() { return this.getWidth()+'px'; } } setObj.prototype.Math = function(value){ var F = function(){}; var overObj = this.constructor.Maths[value]; F.prototype = this; // F构造函数继承setObj var newObj = new F(); for(var i in overObj){ console.log(i); if(overObj.hasOwnProperty(i)){ newObj[i] = overObj[i]; } } return newObj; } var newobj = new setObj(120); console.log(newobj.Math("add"));
这样写完以后,就会出现一个问题,
getWidth 不停的回调 自己。死循环了,所以找一个变量寄存一下原来的 getWidth方法
function setObj(width){ this.width = width||100; } setObj.prototype.getWidth = function(){ return this.width; } setObj.prototype.changeLength = function(width){ this.width = width; return this; } setObj.Maths = {}; setObj.Maths.add = { getWidth: function() { return this.uber.getWidth() + this.uber.getWidth(); } } setObj.Maths.sqr = { getWidth: function() { return this.uber.getWidth() * this.uber.getWidth(); } } setObj.prototype.Math = function(value){ var F = function(){}; var overObj = this.constructor.Maths[value]; F.prototype = this; // F构造函数继承setObj var newObj = new F(); newObj.uber = F.prototype; for(var i in overObj){ if(overObj.hasOwnProperty(i)){ newObj[i] = overObj[i]; } } return newObj; } var newobj = new setObj(120); console.log(newobj.Math("add").Math("sqr").getWidth());
看一下官方案列
function Sale(price){ this.price = price || 100; } Sale.prototype.getPrice = function(){ return this.price; } Sale.decorators = {}; Sale.decorators.fedtax = { getPrice: function(){ var price = this.uber.getPrice(); price += price *7.5 / 100; return price; } } Sale.decorators.money = { //把方法挂在在构造函数上面,这样这个方法就属于这个构造里面 getPrice: function() { return "$" + this.uber.getPrice().toFixed(2); } } Sale.decorators.cdn = { getPrice: function() { return "CDN$" + this.uber.getPrice().toFixed(2); } } Sale.prototype.decorate = function(decorator){ var F = function(){}, overrides = this.constructor.decorators[decorator], i, newobj; F.prototype = this; newobj = new F(); newobj.uber = F.prototype; //newobj拥有了F对象的所有方法 for(i in overrides){ if(overrides.hasOwnProperty(i)){ //重写getPrice方法 newobj[i] = overrides[i]; } } return newobj; } var sale = new Sale(100); var back = sale.decorate("fedtax").decorate("money");
看一下jquery里面是怎么使用的
无论调用什么,返回的都是