Prototype.AjaxRequest的调用堆栈重写问题<o:p></o:p>
作者:cleverpig<o:p></o:p>
<o:p> </o:p>
由于调用AjaxRequest类进行XMLHTTPRequest操作时,this引用(指向当前function所在的对象)会出现了call stack问题,从而指向当前的对象:<o:p></o:p>
错误演示:<o:p></o:p>
var OverWritingDemonstrate=Class.create();<o:p></o:p> OverWritingDemonstrate.prototype={<o:p></o:p> xml_source:'',<o:p></o:p> initialize:function(){<o:p></o:p> },<o:p></o:p> putRequest:function(url,params,callBackFunction){<o:p></o:p> var funcHolder=arguments.callee.$;<o:p></o:p> var xmlHttp = new Ajax.Request(url,<o:p></o:p> {<o:p></o:p> method: 'get', <o:p></o:p> parameters: params, <o:p></o:p> requestHeaders:['my-header-encoding','utf-8'],<o:p></o:p> onFailure: function(){<o:p></o:p> alert('对不起,网络通讯失败,请重新刷新!');<o:p></o:p> },<o:p></o:p> onSuccess: function(transport){<o:p></o:p> },<o:p></o:p> onComplete: function(transport){<o:p></o:p> this.xml_source=transport.responseText;<o:p></o:p> this.showXMLResponse();<o:p></o:p> }<o:p></o:p> });<o:p></o:p> },<o:p></o:p> //显示xml信息<o:p></o:p> showXMLResponse:function(){<o:p></o:p> alert(this.xml_source);<o:p></o:p> },<o:p></o:p> …<o:p></o:p> }<o:p></o:p> |
这样使用必定找不到showXMLResponse方法,因为在AjaxRequest的onComplete函数中的this指向了当前的function所在的对象xmlHttp,而不是我们的OverWritingDemonstrate类对象。<o:p></o:p>
<o:p> </o:p>
Fix方法:<o:p></o:p>
我们可以借鉴一下《解开JavaScript生命的达芬奇密码》中Joshua Gertzen的方法,实现一个ClassUtils类:<o:p></o:p>
//类工具<o:p></o:p> var ClassUtils=Class.create();<o:p></o:p> ClassUtils.prototype={<o:p></o:p> _ClassUtilsName:'ClassUtils',<o:p></o:p> initialize:function(){<o:p></o:p> },<o:p></o:p> /**<o:p></o:p> * 给类的每个方法注册一个对类对象的自我引用<o:p></o:p> * @param reference 对类对象的引用<o:p></o:p> */<o:p></o:p> registerFuncSelfLink:function(reference){<o:p></o:p> for (var n in reference) {<o:p></o:p> var item = reference[n]; <o:p></o:p> if (item instanceof Function) <o:p></o:p> item.$ = reference;<o:p></o:p> }<o:p></o:p> }<o:p></o:p> }<o:p></o:p> |
<o:p> </o:p>
然后修改一下前面的OverWritingDemonstrate,这里为了达到区分效果的目的,类名取为AjaxWrapper:<o:p></o:p>
//Ajax操作封装类:<o:p></o:p> //由于调用AjaxRequest类进行XMLHTTPRequest操作时,this引用(指向当前的对象)会出现了call stack问题,从而指向当前的对象。<o:p></o:p> //所以,对putRequest、callBackHandler、以及callback方法都要使用arguments.callee.$来获得正确的类对象引用<o:p></o:p> var AjaxWrapper=Class.create();<o:p></o:p> AjaxWrapper.prototype={<o:p></o:p> xml_source:'',<o:p></o:p> /**<o:p></o:p> * 初始化<o:p></o:p> * @param isDebug 是否显示调试信息<o:p></o:p> */<o:p></o:p> initialize:function(isDebug){<o:p></o:p> new ClassUtils().registerFuncSelfLink(this);<o:p></o:p> },<o:p></o:p> putRequest:function(url,params,callBackFunction){<o:p></o:p> var funcHolder=arguments.callee.$;<o:p></o:p> var xmlHttp = new Ajax.Request(url,<o:p></o:p> {<o:p></o:p> method: 'get', <o:p></o:p> parameters: params, <o:p></o:p> requestHeaders:['my-header-encoding','utf-8'],<o:p></o:p> onFailure: function(){<o:p></o:p> alert('对不起,网络通讯失败,请重新刷新!');<o:p></o:p> },<o:p></o:p> onSuccess: function(transport){<o:p></o:p> },<o:p></o:p> onComplete: function(transport){<o:p></o:p> funcHolder.xml_source=transport.responseText;<o:p></o:p> funcHolder.showXMLResponse();<o:p></o:p> }<o:p></o:p> });<o:p></o:p> },<o:p></o:p> //显示xml信息<o:p></o:p> showXMLResponse:function(){<o:p></o:p> alert(funcHolder.xml_source);<o:p></o:p> },<o:p></o:p> …<o:p></o:p> }<o:p></o:p> |
这样就避免了发生在调用堆栈中的this重写问题了。<o:p></o:p>
<o:p> </o:p>
代码下载:
demonstrate.rar相关资源:<o:p></o:p>
解开JavaScript生命的达芬奇密码<o:p></o:p>