小议javascript 设计模式 推荐

记得早前就说过要和大家分享“javascript设计模式”,迟迟没写不是因为我懒,最近确实太忙,忙工作,忙旅游(啊哦?),好不容易这几天空闲了,接下来是兑现之前空口白话的时间了。
在讨论设计模式之前,请确认您已经有一定的脚本编程基础,如果不甚了解,建议可以先查阅本人很久之前写的这篇《浅谈javascript面向对象编程》请看下一篇文章。
讲到设计模式,不得不先重点着墨于“接口设计”,因为接口设计在设计模式中的意义太大了,大于模式本身。直观起见,先介绍一下接口定义的形式:


代码如下:

var interface = new Interface("interface",[["getName",1],["getAge",1]]);

可以看出接口函数必须包含两个参数,接口方法定义在一个二维数组中。上例中定义了两个接口方法:getName,getAge,这两个方法都带一个参数,下面我们详细看一下Interface函数的实现代码,从而加深大家对接口的理解。


代码如下:

function Interface(name,methods){
if(arguments.length !=2){
console.log("参数必须为二个");
}
this.name = name;
this.methods = [];
if(methods.length<1){
console.log("第二个参数不能为空数组");
}
for(var i=0;len=methods.length,i<len;i++){
if(typeof methods[i][0] !== 'string'){
console.log("第一个参数数据类型必须为字符串");
}
if(methods[i][1] && typeof methods[i][1] !== 'number'){
console.log("第二个参数数据类型必须为整数型");
}
if(methods[i].length == 1){
methods[i][1] = 0;
}
this.methods.push(methods[i]);
}
}

从代码中不难看出,接口函数的定义规则:[1]Interface函数只能包含两个参数,第一个参数为接口名称,第二个参数是一个二维数组[2]第二个参数不允许为空数组[3]methods参数中的第一个参数必须为字符串类型,用以定义方法名,第二个参数必须为整数类型,用以定义方法的参数个数[4]当methods中方法的参数个数为0时,可以省略不写。
接下来要建一个类,让该类继承前面定义的interface接口,那该怎么做呢,别急,我们需要新增一个方法,见如下代码:


代码如下:

var ioldfish = function(name,age){
this.name = name;
this.age = age;
Interface.regImplement(this,interface);
}
ioldfish.prototype.getName = function(){
alert(this.name);
};
ioldfish.prototype.getAge = function(){
alert(this.age);
};
var fishwl = new ioldfish("老鱼",27);
fishwl.getName();

Interface.regImplement就是我们要新增的方法,作用就是让ioldfish类按照接口interface的规范编码,否则将会在firebug的控制台抛出异常。
看看这个方法的具体实现代码:


代码如下:

Interface.regImplement = function(object){
if(arguments.length<2){
console.log("接口继承参数不能少于二个");
}
for(var i=1;len = arguments.length,i<len;i++){
var interface = arguments[i];
if(interface.constructor !== Interface){
console.log("第三个参数开始必须为接口实例");
}
for(var j=0;len=interface.methods.length,j<len;j++){
var method = interface.methods[j][0];
if(!object[method] || typeof object[method] !=="function" || object[method].getParameters().length !== interface.methods[j][1]){
console.log(""+method+"方法接口不匹配");
}
}
}
}

解读这段代码,你很容易发现:[1]Interface.regImplement继承接口函数的参数至少要有两个,如果有第三个参数,那么该参数必须是Interface接口的实例[2]我们去遍历interface接口中的方法,再与新增类中的方法一一匹配,如果发现继承了该接口规范的类缺少某方法,就会抛出错误提示。[3]接口对于参数个数也进行了匹配,如果接口方法中的参数个数与新增类中方法的个数不匹配也会抛出错误提示。
为了匹配方法中参数个数,这里用到一个getParameters()方法,我们基于Function做个扩展,代码实现如下:


代码如下:

Function.prototype.getParameters = function(){
var str = this.toString();
var paramStr = str.slice(str.indexOf("(")+1,str.indexOf(")")).replace(/\s*/g,'');
try{
return (paramStr.length ==0 ? [] : paramStr.split(","));
}
catch(err){
console.log("非法函数");
}
}

接下来,你可以把所讲的Interface函数,Interface.regImplement函数,还有Function.prototype.getParameters函数整合到一个interface.js的文件中,调试一下新建的这个ioldfish类。看看当类中缺少getAge方法时会怎么样?建议新手,各类情况都模拟一下,加强理解吧!如果你确信已经完全理解接口设计,那就跟着我继续往下走。
Javascript设计模式之单体模式Singleton
单体模式Singleton:这是最基础的设计模式,严格来说没什么模式可言,但是却很容易用也很好用,支付宝很多组件都是通过单体模式设计的。事实上在《浅谈javascript面向对象编程》中阐述原型继承的时候就已经用到了该模式,这里简单带过,重点说一下惰性单体,这对一些不是所有用户都需要,在特定情景下才会用到的组件有非常好的优化作用,他可以让组件的实例化推迟到用户触发他的时候。


代码如下:

var ioldfish = {
name:'老鱼',
age:27,
getName:function(){
alert(name);
},
getAge:function(){
alert(age);
}
}

上例是一个最简单的单体模式,把本人的资料都整合到ioldfish这个对象字面量中,形成一个模块,同时起到了一个命名空间的作用。


代码如下:

var ioldfish =(function(){
var name = '老鱼';
var age = 27;
return{
getName:function(){
alert(name);
},
getAge:function(){
alert(age);
}
}
})();

对第一个单体做简单的修改,通过闭包让name,age成为静态私有变量,确保实例化的时候在内存中始终只有一份,这样更符合单体模式的定义。
下面重点介绍一下惰性单体,废话少说,先看看我们该如何来实现惰性单体:


代码如下:

var ioldfish = (function(){
var uniqueInstance;
var name = '老鱼';
var age = 27;
function constructor(){
return{
getName:function(){
alert(name);
},
getAge:function(){
alert(age);
}
}
}
return{
isInstance:function(){
if(uniqueInstance == null){
uniqueInstance = constructor();
}
return uniqueInstance;
}
}
})();
ioldfish.isInstance().getName();

上面的结构公私分明一目了然,私有变量uniqueInstance(标识类是否已经实例化)和私有方法constructor,返回一个公有方法isInstance(通过该方法可以调用私有方法constructor中定义的方法),形如:ioldfish.isInstance().getName();先通过isInstance()方法判断其是否被实例化,然后通过getName()方法获取到闭包内的私有变量name。该模式的应用场景还是很多的,是不是遇见过页面中需要加载很大的一个日历控件,但并非所有用户都用的到呢?是不是…
Javascript设计模式之工厂模式Factory
工厂模式Factory:先创建一个抽象类,然后基于这个抽象类派生出子类,并在子类中创建工厂方法,从而把实例化推迟到对应的子类中进行,说实话,工厂模式在javascript中的应用有些牵强,毕竟javascript不像java存在硬编码带来的困搅,要学习的只是模式的思想,切忌因为模式而模式。
不妨举个偏激点的例子,为tab切换、下拉列表等组件添加定位,渐隐,延迟等效果,我们可以先为这些组件定义一个接口:
  var Iwidget = new Interface("iwidget",[["addEffect"]]);
定义该接口,以便之后派生的子类继承,接口中定义了一个addEffect方法,接口方法实现后,调用的同学大可不必关注各子类中对于addEffect方法的代码实现。


代码如下:

var Widget = function(){};
Widget.prototype={
fire:function(model){
var widget = this.createWidget(model);
//有同学问为什么子类都必须定义接口方法,因为下面要调用嘛
widget.addEffect();
return widget;
},
show:function(){
//show代码具体实现
},
hide:function(){
//hide代码具体实现
},
createWidget:function(model){
alert('抽象类,不可以实例化')
}
};

上例先定义一个抽象类Widget,做为派生子类的父类,由于考虑到这两类组件都涉及到隐藏和显示一个容器,所以在父类中预先定义好show和hide方法以便子类继承。


代码如下:

var xTab = function(){};
extend(xTab,Widget);
xTab.prototype.createWidget = function(model){
var widget;
switch(model){
case 'position':
widget = new xTabPosition();
break;
case 'anim':
widget = new xTabAnim();
break;
case 'delay':
default:
widget = new xTabDelay();
}
};
var dropDown = function(){};
extend(dropDown,Widget);
dropDown.prototype.createWidget = function(model){
var widget;
switch(model){
case 'position':
widget = new dropDownPosition();
break;
case 'anim':
widget = new dropDownAnim();
break;
case 'delay':
default:
widget = new dropDownDelay();
}
};

子类xTab和dropDown继承了父类,并且重写了createWidget方法,不同的子类根据定位,渐隐,延迟效果分别创建不同的实例,只要创建这些实例的类都实现接口中约定的addEffect方法,至于方法代码如何实现,千篇一律,爱咋整咋整。


代码如下:

var xTabPosition = function(){};
xTabPosition.prototype ={
addEffect:function(){
//具体实现代码
}
};
var dropDownPosition = function(){};
dropDownPosition.prototype ={
addEffect:function(){
//具体实现代码
}
};
var dropDownInstance = new dropDown();
dropDownInstance.fire('position');

以此类推,如果您需要为气泡组件添加这些效果,照葫芦画瓢就可以了,说到这里你可以清楚的看到,这种设计模式大大降低了类和类之间的耦合度,而且可以根据具体的交互需求,实现不同的辅助动作,但是也无可避免的增加了代码实现上的复杂性,事实上这种模式并不适合javascript,毕竟它有别于java,不会有类名硬编码的问题,目的是学习他的设计思想,所以以上示例仅供参考,如无大人在旁,小朋友切勿效仿。
对于javascript爱好者来说,更有价值的应该是工厂模式中讲到的的”缓存(memoization)机制”,书上举了个创建XHR对象的例子来说明该特性,但是效果显然不够明显……
memoization名词解释:把函数的每次执行结果都放入一个键值对(数组也可以,视情况而定)中,在接下来的执行中,在键值对中查找是否已经有相应执行过的值,如果有,直接返回该值,没有才 真正执行函数体的求值部分。很明显,找值,尤其是在键值对中找值,比执行函数快多了
在递归调用的时候,memoization的威力才能更好的显现。下面是一个经典的斐波纳契序列,fib(20) 会把fib这个方法执行21891次,如果是fib(40),这会执行331160281次。


代码如下:

function fib(n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}

再看看如何使用memoization来实现:


代码如下:

var iterMemoFib = (function() {
var cache = [1, 1];
var fib = function(n) {
if (n >= cache.length) {
//将一个递归转换成了一个
for (var i = cache.length; i <= n; i++) {
cache[i] = cache[i - 2] + cache[i - 1];
}
}
return cache[n-1];
}
return fib;
})();

将Function的原型扩展memoize 和unmemoize 方法,这样你可以对任何函数实现memoize和解除memoize,当然,这个方法要慎,对一些不是频繁执行的函数,没必要缓存:


代码如下:

Function.prototype.memoize = function() {
var pad = {};
var self = this;
var obj = arguments.length > 0 ? arguments[i] : null;
var memoizedFn = function() {
// 把参数作为数组保存,作为键,把函数执行的结果作为值缓存起来
var args = [];
for (var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
if (!(args in pad)) {
pad[args] = self.apply(obj, arguments);
}
return pad[args];
}
memoizedFn.unmemoize = function() {
return self;
}
return memoizedFn;
}
Function.prototype.unmemoize = function() {
alert("Attempt to unmemoize an unmemoized function.");
return null;
}

使用方法:fib.memoize();
Javascript设计模式之组合模式
组合模式:运用该设计模式可以通过组合对象添加属性和方法,通过递归批量式的让叶子对象得到组合对象的属性和方法。打个比方我们现在要动态创建一个银行列表,按银行类型分为网上银行类,卡通银行类,并可配置他们是否显示。用组合模式如何实现呢?
第一步还是先定义接口,因为要做到某类银行甚至某个银行是否显示可配置,那么我们先约定2个接口,showBank和hideBank。
var IcardItem = new Interface(”icardItem”,[["showBank"],["hideBank"]]);
接下来先定义卡的组合对象,并设置组合对象的基本方法add,remove,getChild,由于这个类继承了IcardItem接口类,所以还定义了showBank,hideBank这两个接口方法。


代码如下:

var cardMain = function(id){
this.cards = [];
this.element = document.createElement("div");
this.element.id = id;
Interface.regImplement(this,IcardItem);
};
cardMain.prototype = {
add:function(card){
this.cards.push(card);
this.element.appendChild(card.getElement());
},
remove:function(card){
for(i=0;len=this.cards.length,i<len;i++){
if(cards[i] == card){
this.cards.splice(i,1);
break;
}
this.element.removeChild(card.getElement());
}
},
getChild:function(i){
return this.cards[i];
},
getElement:function(){
return this.element;
},
showBank:function(){
this.element.style.display ="block";
for(i=0;len=this.cards.length,i<len;i++){
this.cards[i].showBank();
}
},
hideBank:function(){
this.element.style.display ="none";
for(i=0;len=this.cards.length,i<len;i++){
this.cards[i].hideBank();
}
}
};

然后定义叶子对象类bankLogo用以创建银行logo,这里银行logo都以带class的a标签标识:


代码如下:

var bankLogo = function(bankClassName){
this.element = document.createElement("a");
this.element.className = bankClassName;
Interface.regImplement(this,IcardItem);
};
bankLogo.prototype ={
showBank:function(){
this.element.style.display ="block";
},
hideBank:function(){
this.element.style.display ="none";
},
getElement:function(){
return this.element;
}
};

最后设置一个单体对象,将操作银行的相关信息形成一个模块,方便调用:


代码如下:

var BankAction ={
bankList:[],
addBank:function(card){
this.bankList.push(card);
},
innerBank:function(conId){
for(i=0;len=this.bankList.length,i<len;i++){
var cardObj =this.bankList[i].getElement();
}
document.getElementById(conId).appendChild(cardObj);
}
};

到了实现环节了,实例化生成一个包含所有卡的最外层容器,然后根据卡类,分别生成一个放置银行卡和卡通卡的容器,最后生成各银行卡的实例,并按层级关系形成DOM结构:


代码如下:

var bankDivT = new cardMain("PayCard");//创建最外层容器
var ebankCard = new cardMain("ebankCard");//创建网银类银行卡容器
var ktCard = new cardMain("ktCard");//创建卡通类银行卡容器
var ccbBank = new bankLogo('Ebank-CMB');//创建招行银行卡
var abcBank = new bankLogo('Ebank-ABC');//创建农行银行卡
var abcKtBank = new bankLogo('Kt-ABC');//创建卡通农行卡
ebankCard.add(ccbBank);
ebankCard.add(abcBank);
ktCard.add(abcKtBank);
bankDivT.add(ebankCard);
bankDivT.add(ktCard);
BankAction.addBank(bankDivT);
BankAction.innerBank("bankList");

将动态生成的银行列表,DOM结构形如:


代码如下:

<div id="PayCard">
<div id="ebankCard">
<a class="Ebank-CMB"></a>
<a class="Ebank-ABC"></a>
</div>
<div id="ktCard">
<a class="Kt-ABC"></a>
</div>
</div>

组合模式应用在动态生成用户界面的时候,是非常不错的选择,他可以很大程度的简化粘合性代码,提升维护性。不过还是要慎用,毕竟当叶子对象很多的时候,递归还是存在性能上的问题。
Javascript设计模式之装饰者模式
装饰者模式:可以不创建新的子类,给对象创建新的功能。举例说明:支付宝收银台红包结合余额付款的应用场景。
   var Ieconomics = new Interface("ieconomics",[["getPrice"]]);
首先创建一个组件类,基与该组件实例化的对象,会被作为参数传递给装饰者类,以便装饰者调用到该组件中的各方法。


代码如下:

  var economic = function(){
Interface.regImplement(this,Ieconomics);
};
economic.prototype={
getPrice:function(){
//代码实现
}
};

然后创建一个装饰者抽象类,作为派生装饰者选件类的父类:


代码如下:

  var economicsDecorator = function(economic){
this.economic = economic;
this.regImplement(economic,Ieconomics);
};
economicsDecorator.prototype={
getPrice:function(){
return this.economic.getPrice();
}
};

最后基于上面这个抽象类,派生出一个装饰者选件类:


代码如下:

  //红包装饰者选件类
var coupon = function(economic){
//调用装饰着抽象类的构造函数
economicsDecorator.call(this,economic);
};
extend(coupon,couponDecorator);
coupon.prototype=function(){
//改写getPrice方法
getPrice:function(){
return this.economic.getPrice() - this.getCoupon();
},
getCoupon:function(){
//获取红包总价具体实现
}
};
var myCoupon = new economic();
myCoupon = new coupon(myCoupon);

实现装饰者模式就是这么简单,首先创建一个组件的实例myCoupon,然后将该对象作为参数传递给装饰者选件类coupon。你会发现两句代码中我都把值赋给了变量myCoupon,这是因为他们都实现了同一个接口类,他们之间是可以互换使用的。
看到这里心细的同学可能会发现,我们在coupon类中新增了一个getCoupon方法,目前来看不会有任何问题,但是如果我们继续创建一个购物卷装饰者选件类,然后结合红包一起用呢?


代码如下:

//购物卷装饰者选件类
var voucher = function(economic){
economicsDecorator.call(this,economic);
};
extend(voucher,couponDecorator);
voucher.prototype=function(){
getPrice:function(){
return this.getPrice() - this.getVoucher();
},
getVoucher:function(){
//获取优惠卷总价具体实现
}
};
var myCoupon = new economic();
myCoupon = new coupon(myCoupon);
myCoupon = new voucher(myCoupon);

在这种场景下面getCoupon方法已经找不到了,这是因为voucher装饰myCoupon的时候,它的父类economicsDecorator不包含getCoupon方法,那自然是取不到的了,那该怎么办呢?
分析一下装饰者抽象类economicsDecorator,我们传递了一个myCoupon的引用作为参数,我们可以通过这个参数做一些小动作,获得新增加的方法。
 

代码如下:

 var economicsDecorator = function(economic){
this.economic = economic;
this.interface = Ieconomics;
for(var k in this.economic){
if(typeof this.economic[key] !== "function"){
continue;
var i;
for(i = 0;len = this.interface.methods.length,i < len; i++) {
//通过遍历比较在接口类中是否包含此方法,如果包含返回下一个
if(key == this.interface.methods[i][0]) {
break;
}
}
if(i < this.interface.methods.length)
continue;
var decorator = this;
//采用匿名函数调用方式来定义新方法
(function(methodName) {
decorator[methodName] = function() {
return decorator.economic[methodName]();
};
})(key);
}
}
}
this.regImplement(economic,Ieconomics);
};
economicsDecorator.prototype={
getPrice:function(){
return this.economic.getPrice();
}
};

看上面的代码,我们对装饰者抽象类做了一些修改,这样做是为了确保在装饰者选件类中一旦定义新方法,可以在装饰者抽象类中动态的定义出来。这里只是提供一个使用装饰者模式的思路,具体的实现代码远比这个复杂,由于项目还在开发中,demo暂不提供,支付宝新版收银台发布后,会跟大家再做个详细的设计分享。
Javascript设计模式之桥接模式
桥接模式:将抽象和其实现分离开来,以便二者独立变化。其实很简单,只是在API和具体事件之间增加一个桥梁,从而降低API和使用他的类和对象之间的耦合。
事实上对大多数同学来说桥接模式并不陌生,下面的this.getName就是一种桥接方法,他是外访问的一个接口,他的内部实现是通过访问内部私有变量来实现的,这个方法起到了外部和内部沟通的桥梁作用。


代码如下:

var ioldfish = function(){
var name = '老鱼';
this.getName = function(){
alert(name);
}
}

桥接模式用的最多的还是在事件监听器回调函数。下面这个是获取用户信息的API接口函数:


代码如下:

function getUserInfo(userid,callback){
asyncRequest('GET','userInfo?userid='+userid,function(resp){
callback(resp.responseText);
});
}

接下去我们要做的是把这个API和某个事件的触发建立一个桥梁关系
addEvent(element,'click',bridgeMethod);
function bridgeMethod(e){
getUserInfo(this.userid,function(){
//回调函数实现代码
});
}
这里在element对象click的时候触发函数并不是getIserInfo,而是新建了一个桥接方法bridgeMethod,通过这层桥接使得API接口函数和click事件相对独立,这样大大拓宽了API的适用范围。
Javascript设计模式之适配器模式
适配器模式:打个比方,你维护了一个系统,之前一直都是用prototype框架,但是现在打算新引入YUI框架,那如何让两个框架平稳过度呢
,举个例子,如何将prototype中的$方法转换为YUI中的get方法:


代码如下:

function $(){};
function YAHOO.util.Dom.get=function(el){};
function prototypeToYuiAdapter(){
return YAHOO.util.Dom.get(arguments);
}

你要在prototype中使用yui的get方法,只需要做以下申明即可:
   $ = prototypeToYuiAdapter;
这样的话,在prototype中就可以使用YUI中的get方法了。本人并不是很推崇这种模式,所以不多做阐述,事实上我觉得不到万不得以,我们根本不需要使用这种模式,作为一名负责任的设计者,我宁可做代码重构也不希望使用该模式,只能作为无奈之下的过渡型方案使用。
Javascript设计模式之门面模式,观察者模式
门面模式:这应该是所有脚本框架中都用到的,最基础的设计模式,随便找个框架中定义好的方法看看就行了,比如说YUI中的setStyle方法等等等等。在这里就不多阐述了。
观察者模式:该设计模式应用在javascript上似乎更为牵强,不甚理解,这里就不说了,以免误人子第,如有心得者不吝赐教。
一天时间都耗在这篇博文上了,好象还有很多想写的,看来要把心里想的东西写清楚还是不容易的,再整理整理再说吧,敬请期待!

(0)

相关推荐

  • javascript 设计模式之单体模式 面向对象学习基础

    单体模式(singleton) 单体是在脚本加载时创建的,能将一系列有关联的变量和方法组织为一个逻辑单元,逻辑单元里面的内容通过单一的变量进行访问: 一个单体主要分为三部分 用于访问内部信息的入口变量(如:Sky) 属性(如:nickName/age/timeInfo) 方法(如:sayHello) 基本结构 复制代码 代码如下: var Sky = { /* * 作用一,变量管理 */ nickName: "sky", age: "26", /* * 作用二,加载

  • javascript设计模式之解释器模式详解

    神马是"解释器模式"? 先翻开<GOF>看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如何创建一个抽象语法树.它不涉及语法分析.抽象语法树可用一个表驱动的语法分析程序来完成,也可用手写的(通常为递归下降法)语法分析程序创建,或直接client提供. 解析器: 指的是把描述客户端调用要求的表达式,经过解析,形成一个抽象语法树的程序. 解

  • JS设计模式之惰性模式(二)

    惰性模式:减少代码每次执行时的重复性判断,通过重新定义对象来避免原对象中的分支判断,提高网站性能. 例如针对不同浏览器的事件注册方法: var AddEvent = function(dom, type, fn){ if(dom.addEventListener){ dom.addEventListener(type, fn, false); }else if(dom.attachEvent){ dom.attachEvent('on'+type, fn); }else{ dom['on'+ty

  • JavaScript设计模式之原型模式(Object.create与prototype)介绍

    原型模式说明 说明:使用原型实例来 拷贝 创建新的可定制的对象:新建的对象,不需要知道原对象创建的具体过程: 过程:Prototype => new ProtoExam => clone to new Object; 使用相关代码: 复制代码 代码如下: function Prototype() {     this.name = '';     this.age = '';     this.sex = ''; } Prototype.prototype.userInfo = functio

  • JavaScript 设计模式之组合模式解析

    怎么说呢?!就像是动物(组合对象)一样,当它生下后代(叶对象)时,它的后代就有了某种功能(比如:挖洞,听力好等等):也像是一棵树,它有一个根(组合对象)然后是从这个棵树向外冒出的其他枝杆(组合对象)以及从这些枝杆又向外长的叶子(叶对象).换句话说,就是当祖先已经有了,那么只要从这个祖先衍生出来的其他孩子(包括这个祖先下的其他组合对象)已经就具备了某种功能,看上去貌似又有些像是继承."组合模式"在组合对象的层次体系中有两种类型的对象:叶对象和组合对象.组合模式擅长于对大批对象进行操作.

  • JavaScript 设计模式 安全沙箱模式

    命名空间 JavaScript本身中没有提供命名空间机制,所以为了避免不同函数.对象以及变量名对全局空间的污染,通常的做法是为你的应用程序或者库创建一个唯一的全局对象,然后将所有方法与属性添加到这个对象上. 复制代码 代码如下: /* BEFORE: 5 globals */ // constructors function Parent() {} function Child() {} // a variable var some_var = 1; // some objects var mo

  • 常用的Javascript设计模式小结

    <Practical Common Lisp>的作者 Peter Seibel 曾说,如果你需要一种模式,那一定是哪里出了问题.他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案. 不管是弱类型或强类型,静态或动态语言,命令式或说明式语言.每种语言都有天生的优缺点.一个牙买加运动员, 在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些. 术士和暗影牧师很容易成为一个出色的辅助,而一个背着梅肯满地图飞的敌法就会略显尴尬. 换到程序中, 静态语言里可能需要花很多功夫来实现装饰

  • js如何实现设计模式中的模板方法

    在js中如何实现设计模式中的模板方法? 思路的产生必然要求熟悉js,如何实现?就很简单了,都知道在js中如果定义两个相同名称的方法,前一个方法就会被后一个方法覆盖掉,使用此特点就可以实现模板方法. 例如在实际的项目中有很多页面操作的步骤基本相同,但局部细节却不一样.例如在我所在的项目中,就有很多展示数据库记录的页面,每个页面都存在读取记录,查询记录,增加删除,修改记录等相同的操作,但对应的后台方法却不一样. 复制代码 代码如下: function ListCommon2() { var urlA

  • JavaScript设计模式之观察者模式(发布者-订阅者模式)

    观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式. 复制代码 代码如下: div.onclick  =  function click (){ alert ( "click' ) } 只要订阅了div的click事件. 当点击div的时候, function click就会被触发. 那么到底什么是观察者模式呢. 先看看生活中的观察者模式. 好莱坞有句名言. "不要给我

  • javascript设计模式 接口介绍

    这本书中第一个重要的内容就是接口. 大家对接口应该都不陌生,简单的说接口就是一个契约或者规范.在强类型的面相对象语言中,接口可以很容易的实现.但是在javascript中并没有原生的创建或者实现接口的方式,或者判定一个类型是否实现了某个接口,我们只能利用js的灵活性的特点,模拟接口. 在javascript中实现接口有三种方式:注释描述.属性验证.鸭子模型. note:因为我看的是英文书,翻译水平有限,不知道有些词汇如何翻译,大家只能领会精神了. 1. 注释描述 (Describing Inte

随机推荐