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 相关文章推荐
jQuery load方法用法集锦
Dec 06 Javascript
jQuery bxCarousel实现图片滚动切换效果示例代码
May 15 Javascript
基于javascript实现仿百度输入框自动匹配功能
Jan 03 Javascript
JavaScript驾驭网页-DOM
Mar 24 Javascript
js html css实现复选框全选与反选
Oct 09 Javascript
javascript实现多张图片左右无缝滚动效果
Mar 22 Javascript
jQuery 实现倒计时天,时,分,秒功能
Jul 31 jQuery
js实现延迟加载的几种方法详解
Jan 19 Javascript
JavaScript中filter的用法实例分析
Feb 27 Javascript
vue中使用微信公众号js-sdk踩坑记录
Mar 29 Javascript
layui输入框只允许输入中文且判断长度的例子
Sep 18 Javascript
Vue 基于 vuedraggable 实现选中、拖拽、排序效果
May 18 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+DBM的同学录程序(1)
2006/10/09 PHP
PHP计划任务、定时执行任务的实现代码
2011/04/23 PHP
PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
2014/06/25 PHP
分享一个用Mootools写的鼠标滑过进度条改变进度值的实现代码
2011/12/12 Javascript
JavaScript去除空格的三种方法(正则/传参函数/trim)
2013/02/06 Javascript
firefox浏览器不支持innerText的解决方法
2013/08/07 Javascript
教你用AngularJS框架一行JS代码实现控件验证效果
2014/06/23 Javascript
js单独获取一个checkbox看其是否被选中
2014/09/22 Javascript
javascript实现的右下角弹窗实例
2015/04/24 Javascript
JavaScript中判断两个字符串是否相等的方法
2015/07/07 Javascript
AngularJS基础 ng-disabled 指令详解及简单示例
2016/08/01 Javascript
Node.js+Express+MySql实现用户登录注册功能
2017/07/10 Javascript
动手写一个angular版本的Message组件的方法
2017/12/16 Javascript
jQuery实现可以扩展的日历
2020/12/01 jQuery
解决vue项目本地启动时无法携带cookie的问题
2021/02/06 Vue.js
vue实现桌面向网页拖动文件的示例代码(可显示图片/音频/视频)
2021/03/01 Vue.js
python解决方案:WindowsError: [Error 2]
2016/08/28 Python
python leetcode 字符串相乘实例详解
2018/09/03 Python
在PyTorch中Tensor的查找和筛选例子
2019/08/18 Python
python的mysql数据库建立表与插入数据操作示例
2019/09/30 Python
Python中关于logging模块的学习笔记
2020/06/03 Python
有关pycharm登录github时有的时候会报错connection reset的问题
2020/09/15 Python
python实现excel公式格式化的示例代码
2020/12/23 Python
CSS3轻松实现清新 Loading 效果的简单实例
2016/06/06 HTML / CSS
Clarks鞋法国官方网站:英国其乐鞋品牌
2018/02/11 全球购物
巴西购物网站:Estrela10
2018/12/13 全球购物
《赶海》教学反思
2014/04/20 职场文书
党员自我对照检查材料
2014/08/19 职场文书
教师节学生演讲稿
2014/09/03 职场文书
一份文言文检讨书
2014/09/13 职场文书
工作作风建设心得体会
2014/10/22 职场文书
贷款担保书范本
2015/09/22 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
2019年公司卫生管理制度样本
2019/08/21 职场文书
vue使用localStorage持久性存储实现评论列表
2022/04/14 Vue.js
MySql如何将查询的出来的字段进行转换
2022/06/14 MySQL