用JScript實現VB.Net,C#的[委託Delegate]: (轉)

worldblog發表於2007-12-12
用JScript實現VB.Net,C#的[委託Delegate]: (轉)[@more@]

用實現,的[委託Delegate]:


By:
[Lostinet{lostinet@21cn.com;lostinet@chongjian.com}]
[Sun Mar 17 UTC+0800 2002]


VB.Net,C#的委託把和方法封裝在一個物件內。
今天基於JScript的語法特點,也相應做了類似的功能。


不足之處:
如果Function不是的成員,Object必須允許填加新的屬性。
 例如JScript的物件, 的window,document等;
 不行例如有new Object(".DOM")
如果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 {
 strArguments+="Delegate.Stack().Arguments["+i+"]";
 if(i }
 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 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 {
 strArguments+="Delegate.Coll[+cid+].Arguments["+i+"]";
 if(i }
 if(i>0&&i for(;i {
 strArguments+="Delegate.Coll[+cid+].Delegate.Arguments["+i+"]";
 if(i }

 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 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)
);

 

---------------


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991731/,如需轉載,請註明出處,否則將追究法律責任。

相關文章