jQuery AJAX回调函数this指向问题


Posted in Javascript onFebruary 08, 2010

如在全局作用域调用一个含this的对象,此时当前对象的this指向的是window。为了让this的指向符合自己的意愿,JavaScript提供了两个方法用以改变this的指向,它们是call和apply,当然也有利用闭包来实现的方法。本文通过一个例子来说明这些问题。

先看一段演示代码,这代码只供演示用,没有实际意义。

//一个没有实际意义的socket连接对象 
var socket = 
{ 
connect: function(host, port) 
{ 
alert('Connecting socket server,host:' + host + ',port:' + port); 
} 
}; 
//一个即时通讯类,其中connect方法还将作为AJAX回调函数被调用 
function classIm() 
{ 
this.host = '192.168.1.28'; 
this.port = '8080'; 
this.connect = function(data) 
{ 
socket.connect(this.host, this.port); 
}; 
} 
//实例化即时通讯类 
var IM = new classIm(); 
//AJAX请求,这里假设要打开socket连接首先要通过WEB得知用户WEB登录成功 
$.get('CheckWebLogin.aspx', IM.connect); 
运行上面的例子,你将看到弹出的host与port都是undefined,那是因为回调函数的this不是指向IM对象,而是jQuery的AJAX配置对象ajaxSettings。在jQuery内部是用s.success代替传入的回调函数去执行的,而success的调用对象就是s,即下面ajaxSettings对象的缩写。 ajaxSettings: 
{ 
url: location.href, 
global: true, 
type: "GET", 
contentType: "application/x-www-form-urlencoded", 
processData: true, 
async: true 
}

为了证明这一点,你可以这样修改代码测试一下,你将看到是url、global、type、contentType等对象的属性名称:
this.connect = function(data) 
{ 
for (var key in this) 
{ 
alert(key); 
} 
}

现在了解了问题所在,接下来想办法解决这个问题。其实我们的目的是希望AJAX回调函数代码socket.connect(this.host, this.port)中的this指向类classIm的实例对象IM,或者说是想socket.connect()方法能得到正确的参数值吧。为了得到预期的AJAX回调函数执行结果,我分析了大致有下面几种方法:

方法一

直接传对象的正确引用而非this指针,或叫对象实传。这是最常见的做法,即在类实例化时用一个变量存储对当前对象的引用,在后面的方法中直接使用此变量代替this的使用。注意:这种方法并没有真正改变this的指向。演示代码如下,注意对比前后两次代码的区别,我也特别高亮显示差异部分代码。

var socket = 
{ 
connect: function(host, port) 
{ 
alert('Connecting socket server,host:' + host + ',port:' + port); 
} 
}; 
function classIm() 
{ 
var self = this; 
this.host = '192.168.1.28'; 
this.port = '8080'; 
this.connect = function(data) 
{ 
socket.connect(self.host, self.port); 
}; 
} 
var IM = new classIm(); 
$.get('CheckWebLogin.aspx', IM.connect);

方法二

使用apply加闭包实现真正改变this的指向。下面方法把函数调用时的this对象存到一个临时变量_method,然后又利用闭包把它传给返回的function对象,在这个返回的function中使用apply把调用时对象的this替换为目标对象thisObj。这种方法是很多JavaScript框架的做法,而且下面这个Function原型方法正是我从prototype框架精简而来。注意我是先给Function原型加了Apply方法,这个Apply不是脚本内置的apply,是我自定义的,如果你喜欢可以定个别的名字。

/** 
* 改变jQuery AJAX回调函数this指针指向 
* @param {Object} thisObj 要替换当前this指针的对象 
* @return {Function} function(data){} 
*/ 
Function.prototype.Apply = function(thisObj) 
{ 
var _method = this; 
return function(data) 
{ 
return _method.apply(thisObj,[data]); 
}; 
} 
var socket = 
{ 
connect: function(host, port) 
{ 
alert('Connecting socket server,host:' + host + ',port:' + port); 
} 
}; 
function classIm() 
{ 
this.host = '192.168.1.28'; 
this.port = '8080'; 
this.connect = function(data) 
{ 
socket.connect(this.host, this.port); 
}; 
} 
var IM = new classIm(); 
$.get('CheckWebLogin.aspx', IM.connect.Apply(IM));

方法三

在匿名回调函数中再调用实际的回调处理函数。这种方法虽然可以解决同样的问题的,但是代码有点长和多余,实际开发中是不建议这样做的。这种方法是保证了调用connect方法的对象还是IM对象,从而保证了this指向还是IM对象。代码如下:
$.get('CheckWebLogin.aspx', function(data){IM.connect(data)});
Javascript 相关文章推荐
js 图片等比例缩放代码
May 13 Javascript
location.search在客户端获取Url参数的方法
Jun 08 Javascript
SlideView 图片滑动(扩展/收缩)展示效果
Aug 01 Javascript
一个简单的Ext.XTemplate的实例代码
Mar 18 Javascript
JS中实现简单Formatter函数示例代码
Aug 19 Javascript
浅谈js里面的InttoStr和StrtoInt
Jun 14 Javascript
JavaScript实现简单的拖动效果
Jul 02 Javascript
详解基于webpack和vue.js搭建开发环境
Apr 05 Javascript
使用vue打包时vendor文件过大或者是app.js文件很大的问题
Jun 29 Javascript
详解js获取video任意时间的画面截图
Apr 17 Javascript
微信小程序如何加载数据库真实数据的实现
Mar 04 Javascript
原生JavaScript实现弹幕组件的示例代码
Oct 12 Javascript
JavaScript Event学习第九章 鼠标事件
Feb 08 #Javascript
JavaScript 类似flash效果的立体图片浏览器
Feb 08 #Javascript
js 省地市级联选择
Feb 07 #Javascript
js 自定义的联动下拉框
Feb 07 #Javascript
比较搞笑的js陷阱题
Feb 07 #Javascript
javascript 鼠标拖动图标技术
Feb 07 #Javascript
数组Array进行原型prototype扩展后带来的for in遍历问题
Feb 07 #Javascript
You might like
php 结果集的分页实现代码
2009/03/10 PHP
sourcesafe管理phpproj文件的补充说明(downmoon)
2009/04/11 PHP
php 根据url自动生成缩略图并处理高并发问题
2014/01/23 PHP
PHP错误WARNING: SESSION_START() [FUNCTION.SESSION-START]解决方法
2014/05/04 PHP
PHP常用函数总结(180多个)
2016/12/25 PHP
php创建图像具体步骤
2017/03/13 PHP
Thinkphp5结合layer弹窗定制操作结果页面
2017/07/07 PHP
PHP利用百度ai实现文本和图片审核
2019/05/08 PHP
使用swoole 定时器变更超时未支付订单状态的解决方案
2019/07/24 PHP
BOOM vs RR BO5 第三场 2.14
2021/03/10 DOTA
Prototype Function对象 学习
2009/07/12 Javascript
extjs之去除s.gif的影响
2010/12/25 Javascript
分享8款优秀的 jQuery 加载动画和进度条插件
2012/10/24 Javascript
jQuery中校验时间格式的正则表达式小结
2013/09/22 Javascript
js实现改进的仿蓝色论坛导航菜单效果代码
2015/09/06 Javascript
vue中的适配px2rem示例代码
2018/11/19 Javascript
Vue2(三)实现子菜单展开收缩,带动画效果实现方法
2019/04/28 Javascript
layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法
2019/09/21 Javascript
JS eval代码快速解密实例解析
2020/04/23 Javascript
Node使用koa2实现一个简单JWT鉴权的方法
2021/01/26 Javascript
python石头剪刀布小游戏(三局两胜制)
2021/01/20 Python
浅谈Scrapy网络爬虫框架的工作原理和数据采集
2019/02/07 Python
Python实现求两个数组交集的方法示例
2019/02/23 Python
对python 树状嵌套结构的实现思路详解
2019/08/09 Python
tensorflow获取预训练模型某层参数并赋值到当前网络指定层方式
2020/01/24 Python
意大利综合购物网站:Giordano Shop
2016/10/21 全球购物
澳大利亚首个在线预订旅游网站:Wotif
2017/07/19 全球购物
宿舍使用违章电器检讨书
2014/01/12 职场文书
初二生物教学反思
2014/02/03 职场文书
银行职员个人的工作自我评价
2014/02/15 职场文书
大学生学雷锋活动总结
2014/06/26 职场文书
写给老婆的保证书
2015/02/27 职场文书
Python用tkinter实现自定义记事本的方法详解
2022/03/31 Python
Golang MatrixOne使用介绍和汇编语法
2022/04/19 Golang
cypress测试本地web应用
2022/06/01 Javascript
spring 项目实现限流方法示例
2022/07/15 Java/Android