用JScript实现VB.Net,C#的[委托Delegate]:
By: [Lostinet{lostinet@21cn.com;lostinet@chongjian.com}] [Sun Mar 17 UTC+0800 2002]
VB.Net,C#的委托把对象和方法封装在一个对象内。 今天基于JScript的语法特点,也相应做了类似的功能。
不足之处: 如果Function不是Object的成员,Object必须允许填加新的属性。 例如JScript的对象,DHTML DOM的window,document等; 不行例如有new ActiveXObject("Microsoft.XMLDOM") 如果Function不是Object的成员,在Function调用的时候,必须为Object填加一个 var theIndex="delegate function "+new Date()+" "+Math.random(); => Object[theIndex]=Function 所以在for(var i in Object)的结构中,theIndex也会出现。
注意事项: 一旦delegate被引用,那么相关的object,function就不会被释放。 要完全释放object,function,必须先释放相关的delegate
脚本和解释如下:
//返回FunctionSelf的调用者,任何函数调用FunctionSelf将返回该函数本身 function FunctionSelf(){return FunctionSelf.caller} /* 返回封装了obj,func的delegate 例如已知对象和函数:obj1.func1 那么调用obj1.func1(1,2,3) 和调用Delegate(obj1,obj1.func1)(1,2,3) 将会是相似的(除了上面提及的不足之处)
除了这个函数是公开的,其他函数不应该擅自调用。 obj :指定对象 funcOrIndex :指定函数的引用,或者是属于obj的一个名字 */ function Delegate(obj,funcOrIndex) { var delegate=new Function("","FunctionSelf().Call(FunctionSelf().arguments)"); delegate.Object=obj; delegate.Call=Delegate.Call; if(typeof(funcOrIndex)=="string") { delegate.Index=funcOrIndex; delegate.Function=obj[funcOrIndex]; } else { delegate.Index=null; delegate.Function=funcOrIndex; } if(typeof(delegate.Function)!="function")throw("没有指定函数!"); return delegate; } //当delegate被调用时,这个函数就会被调用。 function Delegate.Call(arguments) { /* 涉及到function.arguments允许动态的个数,所以选择了eval来执行。 当一个delegate被调用时,有全局的变量代表了当前被封装的Object,Function,Arguments的集合, 以便被eval调用 */ //压入当前的delegate的情况 Delegate.Stack.Push(this,arguments); var strArguments=""; for(var i=0;i<arguments.length;i++) { strArguments+="Delegate.Stack().Arguments["+i+"]"; if(i<arguments.length-1)strArguments+=","; } if(this.Index) var theIndex=this.Index; else { var theIndex="delegate function "+new Date()+" "+Math.random(); this.Object[theIndex]=this.Function; } var strEval="Delegate.Stack().Delegate.Object[\""+theIndex+"\"]("+strArguments+");"; try//运行delegate,释放当前的delegate的情况 { eval(strEval); } catch(x) { //exception的发生可以返回。
//当delegate被嵌套调用时, //如果中途没有被处理。那么就会返回到最外层 if(!this.Index)delete this.Object[theIndex]; Delegate.Stack.Pop(this); throw(x); } if(!this.Index)delete this.Object[theIndex];//如果是自定义的Index,那么就要删除 Delegate.Stack.Pop(); } //新建一个全局使用的变量 function Delegate.StackObject(delegate,arguments) { this.Delegate=delegate; this.Arguments=arguments; } //返回堆栈当前的对象 function Delegate.Stack() { return Delegate.Stack.Object; } //Stack的数据 function Delegate.Stack.Array(){} //因为调用是堆栈形式的,所以数据也是堆栈的。 //压入当前delegate调用的状态。 function Delegate.Stack.Push(delegate,arguments) { if(typeof(Delegate.Stack.Position)=="undefined")Delegate.Stack.Position=-1; Delegate.Stack.Position++; Delegate.Stack.Object=new Delegate.StackObject(delegate,arguments); Delegate.Stack.Array[Delegate.Stack.Position]=Delegate.Stack.Object; } //Release function Delegate.Stack.Pop() { Delegate.Stack.Array[Delegate.Stack.Position]=null; Delegate.Stack.Position--; }
//下面、是例子:
function myalert(str) { try{WScript.Echo(str)}catch(x){} try{alert(str)}catch(x){} }
var obj=new Object(); obj.value="the obj.value :)"; function func(a,b,c) { var str=""; var count=0; for(var i in this) { count++; str+=i+":"+typeof(this[i])+"\n"; } var str="a,b,c="+a+":"+b+":"+c+"\nthis.value="+this.value+"\n"+count+"\n"+str; myalert(str); } var delegate=Delegate(obj,func);//传递函数引用 delegate(3,33,333); obj.callthefunc=func;//或者是:obj["callthefunc"]=func; delegate=Delegate(obj,"callthefunc");//传递名字 delegate(4,5,6);
var xml=new ActiveXObject("Microsoft.XMLDOM"); var xmlo=new Object(); xmlo.xml=xml; xmlo.name="xmlo"; xml.onreadystatechange=Delegate(xmlo,onreadystatechange); xml.load("test1.xml");
var xml2=new ActiveXObject("Microsoft.XMLDOM"); var xmlo2=new Object(); xmlo2.xml=xml2; xmlo2.name="xmlo2"; xml2.onreadystatechange=Delegate(xmlo2,onreadystatechange); xml2.load("test2.xml");
function onreadystatechange() { if(this.xml.readyState!=4)return;//not ready if(this.xml.parseError.errorCode) myalert(this.name+this.xml.parseError.reason); else myalert(this.xml.xml); }
---------------2002.3.8:-------------
function FunctionSelf(){return FunctionSelf.caller;} function Delegate(obj,funcOrName) { var delegate=new Function("","return FunctionSelf().Invoke(FunctionSelf().arguments)");
delegate.Arguments=new Array(); delegate.Object=obj; delegate.UniqueName="DelegateUniqueID"+Math.floor((new Date().getTime()+Math.random())*1000); if(typeof(funcOrName)=="string") { delegate.FuncName=funcOrName; delegate.Function=obj[delegate.FuncName]; } else { delegate.FuncName=null; delegate.Function=funcOrName; }
delegate.Invoke=Delegate.Invoke; delegate.Detach=Delegate.Detach; delegate.SetArguments=Delegate.SetArguments; delegate.PreInvoke=Delegate.PreInvoke; delegate.valueOf=new Function("","return \""+delegate.UniqueName+"\""); delegate.toString=new Function("","return \""+delegate.UniqueName+"\"");
return delegate; } function Delegate.GetCaller() { var cid=FunctionSelf().caller.caller.CallID; return Delegate.Coll[cid]; } function Delegate.GetDelegate() { var cid=FunctionSelf().caller.caller.CallID; return Delegate.Coll[cid].Delegate; } function Delegate.PreInvoke() { this.SetArguments(Delegate.PreInvoke.arguments); return this; } function Delegate.SetArguments(args) { if(args==null)args=new Array(); this.Arguments=new Array(); for(var i=0;i<args.length;i++)this.Arguments[i]=args[i]; return this; } function Delegate.Invoke(args) { if(this.Object==null)return; var cid=Delegate.Coll.Insert(this,args); var strArguments=""; var i=0; for(i=0;i<args.length;i++) { strArguments+="Delegate.Coll[''''"+cid+"''''].Arguments["+i+"]"; if(i<args.length-1)strArguments+=","; } if(i>0&&i<this.Arguments.length)strArguments+=","; for(;i<this.Arguments.length;i++) { strArguments+="Delegate.Coll[''''"+cid+"''''].Delegate.Arguments["+i+"]"; if(i<this.Arguments.length-1)strArguments+=","; }
var funcName=this.FuncName||cid; if(this.FuncName==null)this.Object[funcName]=this.Function; var res; var exception; try { res=eval("new Function('''''''',\"FunctionSelf().CallID=''''"+cid+"'''';return Delegate.Coll[''''"+cid+"''''].Delegate.Object[''''"+funcName+"'''']("+strArguments+")\")()"); }catch(x){exception=x} if(this.Object&&(this.FuncName==null))delete this.Object[funcName]; Delegate.Coll.Remove(cid); if(exception)throw(exception); return res; } function Delegate.Detach() { this.Object=null; this.Function=null; this.FuncName=null; this.UniqueName=null; } function Delegate.EvalCaller(delegate,args,cid) { this.Delegate=delegate; this.Arguments=args; this.CallID=cid; } function Delegate.Coll(){} function Delegate.Coll.Insert(delegate,args) { if(typeof(Delegate.Coll.Length)=="undefined")Delegate.Coll.Length=0; Delegate.Coll.Length++; var cid=delegate.UniqueName+"call"+Math.floor((new Date().getTime()+Math.random())*1000); var EvalCaller=new Delegate.EvalCaller(delegate,args,cid); Delegate.Coll[cid]=EvalCaller; return cid; } function Delegate.Coll.Remove(cid) { delete Delegate.Coll[cid]; Delegate.Coll.Length--; }
--------------------例子:
function myjoin() { var str=""; for(var i=0;i<myjoin.arguments.length;i++) str+=myjoin.arguments[i]; return str; } alert( Delegate(new Object(),myjoin) .PreInvoke(1,2,3,4,5,6,7,8,9) .PreInvoke("a","b","c","d","e") (9,8,7,6) );
---------------
[C语言系列]NET 中C#的switch语句的语法 [系统软件]托拽Explore中的文件到VB.net的窗口 [系统软件]Boost库在XP+Visual C++.net中的安装 [系统软件]14.5.10.3 Delegate creation expressions [常用软件]新配色面板:Paint.Net3.0RC1官方下载 [常用软件]用内建的“Net Meeting”聊天 [VB.NET程序]Henry的VB.NET之旅(三)—共享成员 [VB.NET程序]Henry的VB.NET之旅(二)—构造与析构 [VB.NET程序]Henry的VB.NET之旅(一)—失踪的窗体 [VB.NET程序]在托盘上显示Balloon Tooltip(VB.NET)
|