1、背景
Javascript中的回调函数,相信大家都不陌生,最明显的例子是做Ajax请求时,提供的回调函数,
实际上DOM节点的事件处理方法(onclick,ondblclick等)也是回调函数。
在使用DWR的时候,回调函数可以作为第一个或者最后一个参数出现,如:
function callBack(result){
}
myDwrService.doSomething(param1,param2,callBack);//DWR的推荐方式
//或者
myDwrService.doSomething(callBack,param1,param2);
2、问题描述
最近在使用Dojo+Dwr的时候,碰到一个问题:
如果回调函数是属于某个对象(记为obj1)的方法,等到DWR执行该回调函数的时候,
上下文却不是obj1。
表现的现象就是在回调函数中访问obj1的任何属性都是undefined。
版本:Dojo1.3.1和dwr2
3、模拟问题的代码
下面的测试代码可以模拟这个问题:
<html>
<head>
<script>
var context="全局";
var testObj={
context:"初始",
callback:function (str){//回调函数
alert("callback:我所处的上下文中,context="+this.context+",我被回调的方式:"+str);
}
};//创建一个对象,作为测试回调函数的上下文
testObj.context="已设置";
function testCall(){
callMethod(testObj.callback);
callObjMethod(testObj,testObj.callback);
}
function callObjMethod(obj,method){
method.call(obj,"指定显式对象上下文回调");
}
function callMethod(method){
method("通过默认上下文回调");
}
</script>
</head>
<body>
<a href="javascript:void(0)" onclick="testCall()">调用测试</a>
</body>
</html>
在testCall方法中,我用了两种方式回调“testObj.callback"方法:
第一种方式:method("通过默认上下文回调");
没有指定上下文,我们发现回调函数内部访问context的值是全局变量的值,
这说明,执行该方法的默认上下文是全局上下文。
第二种方式:method.call(obj,"指定显式对象上下文回调");
指定obj为method执行的上下文,就能够访问到对象内部的context。
4、研究DWR
因为06年使用DOJO+DWR(1.0)的时候,已经遇到过这个问题,当时没做太多功课,直接改了dwr的源代码。
现在用dwr2,于是想先看看DWR是不是对这个问题有新的处理方式,
将dwr.jar中的engine.js拿出来,查看了有关回调的相关代码(_remoteHandleCallback和_execute),
发现对回调的处理方式似乎比1.0更简单,没办法将对象和方法一起传过去。
5、做进一步的研究
因为这次DWR在项目中的使用太广泛,而且我相信这样的需求应该是可以满足的,于是没有立刻修改源码,
首先,在Google上搜Dojo+dwr,没有查到什么结论,可能Dojo的用户不是太多。
于是又搜”javascript callback object context“,得到一篇文章专门介绍java回调函数的文章:
http://bitstructures.com/2007/11/javascript-method-callbacks
最重要的一句话:
When a function is called as a method on an object (obj.alertVal()),
"this" is bound to the object that it is called on (obj).
And when a function is called without an object (func()),
"this" is bound to the JavaScript global object (window in web browsers.)
这篇文章也提供了解决方案,就是使用Closure和匿名方法,
javascript中,在function内部创建一个function的时候,会自动创建一个closure,
而这个closure就能记住对应的function创建时的上下文。
所以,如果这样:
var closureFunc=function(){
testObj.callback();
}
那么无论在什么地方,直接调用closureFunc()和调用testObj.callback()是等价的。
详情参见上面提到的文章:http://bitstructures.com/2007/11/javascript-method-callbacks。
6、改进模拟代码
在模拟代码中,我们再增加一种回调方式:
<html>
<head>
<script>
var context="全局";
var testObj={
context:"初始",
callback:function (str){//回调函数
alert("callback:我所处的上下文中,context="+this.context+",我被回调的方式:"+str);
}
};//创建一个对象,作为测试回调函数的上下文
testObj.context="已设置";
function testCall(){
callMethod(testObj.callback);
callWithClosure(function(param){testObj.callback(param);});
callObjMethod(testObj,testObj.callback);
}
function callObjMethod(obj,method){
method.call(obj,"指定显式对象上下文回调");
}
function callMethod(method){
method("通过默认上下文回调");
}
function callWithClosure(method){
method("通过Closure保持上下文回调");
}
</script>
</head>
<body>
<a href="javascript:void(0)" onclick="testCall()">调用测试</a>
</body>
</html>
测试以上代码,我们可以发现,通过Closure和通过显示指定对象得到的效果一致。
7、模拟更加真实的调用情景
但是以上代码还有一个问题,在真实环境中,如果回调函数是对象中方法,那么发起请求的方法通常也在同一个对象,
在javascript中,this也可以代表当前对象,但不能直接用在匿名function中用,比如:
var testObj={
context:"初始",
callback:function (str){//回调函数
alert("callback:我所处的上下文中,context="+this.context+",我被回调的方式:"+str);
},
caller:function(){
callWithClosure(function(param){this.callback(param);});
}
};//创建一个对象,作为测试回调函数的上下文
以上代码中的this指的不是testObj,而是全局上下文,
需要在closure外写一个临时变量来代表this,完整的代码如下:
<html>
<head>
<script>
var context="全局";
var testObj={
context:"初始",
callback:function (str){//回调函数
alert("callback:我所处的上下文中,context="+this.context+",我被回调的方式:"+str);
},
caller:function(){
callWithClosure(function(param){this.callback(param);});
var temp=this;
callWithClosure(function(param){temp.callback(param);});
}
};//创建一个对象,作为测试回调函数的上下文
testObj.context="已设置";
function testCall(){
callMethod(testObj.callback);
testObj.caller();
callWithClosure(function(param){testObj.callback(param);});
callObjMethod(testObj,testObj.callback);
}
function callObjMethod(obj,method){
method.call(obj,"指定显式对象上下文回调");
}
function callMethod(method){
method("通过默认上下文回调");
}
function callWithClosure(method){
method("通过Closure保持上下文回调");
}
function callback(str){
alert("callback:我是定义在外部的全局函数。");
}
</script>
</head>
<body>
<a href="javascript:void(0)" onclick="testCall()">调用测试</a>
</body>
</html>
8、什么是Closure
Two one sentence summaries:
a closure is the local variables for a function - kept alive after the function has returned,
or
a closure is a stack-frame which is not deallocated when the function returns. (as if a 'stack-frame' were malloc'ed instead of being on the stack!)
详情参见:http://blog.morrisjohns.com/javascript_closures_for_dummies
分享到:
相关推荐
组装排量0.16CC超微型发动机,果真是麻雀虽小五脏俱全
在IT行业中,前端框架的发展日新月异,Vue.js作为其中的一员,因其轻量级、易上手且功能强大的特点,深受开发者喜爱。本示例项目"基于Vue的TodoList"是一个经典的学习案例,它虽然小巧,但却包含了Vue.js开发中的...
麻雀虽小!五脏俱全!全站生成静态网页!不错的html编辑器,编辑时具有文章标题的推荐,头条,滚动功能!生成静态网页后,即使卸载了数据库!对网站访问,没有丝毫影响!集合了后台SEO参数高级设置、前台全静态生成...
C#运控框架 雷赛运动控制 DMC系列 运动控制项目 C#源码 1.别看它界面丑,里面的应有应该尽有; 2.麻雀虽小五脏俱全,很适合新手的一个学习项目,绝对推荐
描述中提到“麻雀虽小五脏俱全”,意味着这个软件虽然体积小,但包含了各种必要的图像处理功能。它提供了从基本的裁剪、调整大小,到更复杂的色彩校正、滤镜应用等一应俱全的工具。用户可以“很简单的制作出很专业的...
闲暇之余写了个管理系统包括仓库管理,宿舍管理,人事管理,麻雀虽小五脏俱全,各项功能都有,有用的希望能帮助你们!欢迎评论一起进步!系统配置文件用的ini,目录下的DrDepot.ini,所以你们在打开时注意配置里面的...
麻雀虽小,五脏俱全加强版聊天室,源码来自网上搜得的,增加用户登录密码检查,聊天信息记录功能,版权归原作者所有,我只是修改下玩。在终端下执行,没有图形界面,没有创建子进程,利用int型数组保存客户accept套...
这个liteduino真的是太精简了,连个复位按钮都没有,要复位就请手动把RESET接到地再松开,但是麻雀虽小五脏俱全,功能还是有保障的,适合嵌入式,自己玩玩也可以,稳定性不比pro mini(说UNO也行,都是一个芯片,...
一个比较有意思的js库可以为javascript的对象实现观察者模式,以往我们使用javascript实现的观察者模式都是通过使用回调函数配合dom上的event事件来操作的,而“Watch.js”可以为javascript的对象实现观察者模式,...
主要包括: 增、删、改、查,分页显示数据信息, 管理员登录,验证码,JS刷新验证码,session的应用以及销毁,管理员账号和密码修改, JS控制数据信息(全选、反选、取消选择),选择性删除留言,回复留言等...
管理系统是一种通过计算机技术实现的用于组织、监控和控制各种活动的软件系统。这些系统通常被设计用来提高效率、减少错误、加强安全性,同时提供数据和信息支持。以下是一些常见类型的管理系统: ...
现在Javascript框架、控件库有很多,jQuery、Ext、prototype、MooTools、Dojo等等,这些都是在Google上搜索“javascript+framework”列在第一页的。其中,除了MooTools,其它的都有所了解,但只在项目中用过Ext和...
青云是一套麻雀虽小但五脏俱全的在线考试系统。采用了目前主流的技术栈SpringBoot+Vue+ElementUI,并进行了前后端
springMVC+mongodb-java-driver+mongodb+mave+jfreechart-Demo麻雀虽小五脏俱全了,手麻系统是用此框架搭建的,一个简单的demo左边调价号的下拉列表于下面的表格名称,价格是联动的(下拉列表的数据发现改变表格里的...
这款被描述为"麻雀虽小,五脏俱全"的绘图工具,显然尽管其体积小巧,但功能却十分齐全,满足了用户在多种场景下的需求。 首先,让我们深入探讨一下它所支持的一些核心功能。插入便签功能允许用户在绘图过程中添加...
而swoole扩展是提供了更底层的服务器通信机制,可以使用UDP、TCP等协议,而不仅仅是http。 安装方式上也不一样,swoole扩展像其它PHP扩展一样安装,可以用pecl,也可以编译安装。而swoole框架用composer引入之后...
就是一个电脑,只不过是微型的,麻雀虽小,五脏俱全:它内部也用和电脑功能类似的模块,比如CPU,内存,并行总线,还有和硬盘作用相同的存储器件,不同的是它的这些部件性能都相对我们的家用电脑弱很多,不过价钱也...
一、大致设想 1.坦克类,子弹类,每个类维护一张地图 * 关于坦克:地图中只保存当前坦克不能过的地方(墙、河流) * 关于子弹:地图中只保存子弹能撞到的东西(不在草地里的坦克,子弹,墙) * 游戏对象:地图中只...