不知道在这儿说“Decorator模式”是否合适,JS不是面向对象的语言,又是弱语言类型,设计模式是面向对象语言的。两者似乎相差很远。
不过正是因为JS是弱语言类型,造成这种“Decorator模式”。其实作为模式的一种,Decorator或是其它模式没有必要一定要有固定的UML图,或是一定要是面向对象的,它只是一种思想。我理解的Decorator是:
给一个对象添加一些额外的职责
如果我们把JS中的一些函数也看成是“对象”的话,我们再来看看在JS中如何对它们进行“装饰”。
一、利用JS“重载”方法
突然发现JS有一种很好的机制(实际上是一位JS高人指点我的,嘿嘿),它可以“重载”一些函数,利用这种功能我们可以进行动态“重载”。参考以下代码:
window.alert=a;
![](/Images/OutliningIndicators/None.gif)
function a()
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
![](/Images/OutliningIndicators/InBlock.gif)
window.location='http://localhost/a.aspx';
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)
然后我们在这个页面上来一个alert(‘abc’)会有什么反应?页面不会弹出提示框,而是转向上边这个URL。也就是说运行alert时是执行函数a,而不是系统默认的函数了。
二、使用JS“重载”为老函数添加新的职责
我们可以在老函数的基础上动态地添加新的功能,同时又保持原来的函数签名。我认为这已经做成了Decorator,参考以下代码:
运行一下会得到什么?在提示消息出来后,页面跳转到http://localhost/quickstart/
<BODY>
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<SCRIPT LANGUAGE="JavaScript">![](https://www.cnblogs.com/Images/dot.gif)
![](/Images/OutliningIndicators/InBlock.gif)
<!--
![](/Images/OutliningIndicators/InBlock.gif)
var temp=window.alert;
![](/Images/OutliningIndicators/InBlock.gif)
window.alert=a;
![](/Images/OutliningIndicators/InBlock.gif)
function a(alertValue)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
{
![](/Images/OutliningIndicators/InBlock.gif)
temp(alertValue);
![](/Images/OutliningIndicators/InBlock.gif)
window.location='http://localhost/quickstart/';
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
alert(' Microsoft 快速入门教程');
![](/Images/OutliningIndicators/InBlock.gif)
//-->
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
</SCRIPT>
![](/Images/OutliningIndicators/None.gif)
</BODY>
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
过程:
通过声明一个temp变量来保存系统原来的alert函数;
把系统的函数赋上新的方法(函数指针?^_^),新的方法意味着新的职责。
在新的方法中再调用temp中保存的原来的系统函数。
三、实际应用
某个项目有不少页面用到了window.open方法,且实现方法各种各样,有直接写在JS中的,有在codebehind中response的,也有利用.NET注册脚本块的,而且各个参数也不同。突然在项目中有需要变更,要求所有的popup全部居中,如果此时对window.open方法一个一个找出来再修改的话,估计会让人疯掉。
这种情况下我们可以在所有页面的基类(commonpage)重写window.open,为它添加“居中”的职责并保持原来的函数签名,即那三个参数不变,从而实现对项目中所有的open都居中。
参考代码如下:
'by dingsea 11-21
'for adjusting the pop window to center.
Private Function RegisterScriptToAdjustPopWindow() As String
Dim sPop As StringBuilder = New StringBuilder("<SCRIPT LANGUAGE=" + Chr(34) + "JavaScript" + Chr(34) + ">" + Chr(13))
sPop.Append("var o=window.open;" + Chr(13))
sPop.Append("window.open=launchCenter;" + Chr(13))
sPop.Append("function launchCenter(url,name,features)" + Chr(13))
sPop.Append("{" + Chr(13))
sPop.Append("var width=features.substring((features.indexOf('width=')+6));" + Chr(13))
sPop.Append("width=width.substring(0,width.indexOf(','));" + Chr(13))
sPop.Append("var height=features.substring((features.indexOf('height=')+7));" + Chr(13))
sPop.Append("height=height.substring(0,height.indexOf(','));" + Chr(13))
sPop.Append("features+=',innerHeight='+height;" + Chr(13))
sPop.Append("features+=',innerWidth='+width;" + Chr(13))
sPop.Append("if (window.screen) {" + Chr(13))
sPop.Append(" features += ',top='+(screen.availHeight- height)*0.5+',left='+(screen.availWidth-width)*0.5;" + Chr(13))
sPop.Append("}" + Chr(13))
sPop.Append("o(url,name,features);" + Chr(13))
sPop.Append("}" + Chr(13))
sPop.Append("</script>")
![](/Images/OutliningIndicators/None.gif)
Return sPop.ToString
End Function
在页面加载时使用以上代码:
Private Sub Page_PreRender(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
Response.Write(RegisterScriptToAdjustPopWindow()) 'by dingsea
End Sub
为什么不使用.NET自带的注册脚本块?我是想让这个重写代码在页面的最上方,如果用注册脚本块,会出现在BODY之内或是别的什么地方,而如果我直接在page render的时候就response,它会在HTML和所有JS之前被发送到客户端,从而保证页面任何window.open都可以居中。