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 相关文章推荐
JavaScript延迟加载
Mar 09 Javascript
繁简字转换功能
Jul 19 Javascript
javascript setTimeout()传递函数参数(包括传递对象参数)
Apr 07 Javascript
Javascript 面试题随笔
Mar 31 Javascript
getComputedStyle与currentStyle获取样式(style/class)
Mar 19 Javascript
JS实现随机乱撞彩色圆球特效的方法
May 05 Javascript
JS实现弹出浮动窗口(支持鼠标拖动和关闭)实例详解
Aug 06 Javascript
JavaScript模拟push
Mar 06 Javascript
Vue.js每天必学之构造器与生命周期
Sep 05 Javascript
jquery实现联想词搜索框和搜索结果分页的示例
Oct 10 jQuery
vue跳转同一个组件,参数不同,页面接收值只接收一次的解决方法
Nov 05 Javascript
Javascript使用integrity属性进行安全验证
Nov 07 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
在Zeus Web Server中安装PHP语言支持
2006/10/09 PHP
PHP生成带有雪花背景的验证码
2008/09/28 PHP
PHP中session跨子域的三种实现方法
2016/07/25 PHP
PHP使用GD库输出汉字的方法【测试可用】
2016/11/10 PHP
jQuery EasyUI API 中文文档 - ProgressBar 进度条
2011/09/29 Javascript
javascript分页代码(当前页码居中)
2012/09/20 Javascript
JQUERY 实现窗口滚动搜索框停靠效果(类似滚动停靠)
2013/03/27 Javascript
ie8 不支持new Date(2012-11-10)问题的解决方法
2013/07/31 Javascript
浅谈javascript回调函数
2014/12/07 Javascript
JavaScript插件化开发教程 (四)
2015/01/27 Javascript
每天一篇javascript学习小结(面向对象编程)
2015/11/20 Javascript
详解JavaScript中基于原型prototype的继承特性
2016/05/05 Javascript
angularjs 的数据绑定实现原理
2018/07/02 Javascript
vue 实现微信浮标效果
2019/09/01 Javascript
基于Element封装一个表格组件tableList的使用方法
2020/06/29 Javascript
[01:13:46]iG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python压缩文件夹内所有文件为zip文件的方法
2015/06/20 Python
Python实现针对json中某个关键字段进行排序操作示例
2018/12/25 Python
html5 拖拽上传图片实例演示
2013/04/01 HTML / CSS
泰国时尚电商:POMELO Fashion
2020/03/11 全球购物
Cynthia Rowley官网:全球领先的生活方式品牌
2020/10/27 全球购物
大学生实习期自我评价范文
2013/10/03 职场文书
应聘教师自荐信
2013/10/12 职场文书
个人授权委托书范本
2014/04/03 职场文书
师恩难忘教学反思
2014/04/27 职场文书
员工安全承诺书
2014/05/22 职场文书
法定代表人授权委托书范文
2014/08/02 职场文书
活动总结结尾怎么写
2014/08/30 职场文书
科级干部群众路线教育实践活动个人对照检查材料
2014/09/19 职场文书
2014流动人口计划生育工作总结
2014/12/20 职场文书
慈善募捐倡议书
2015/04/27 职场文书
目标责任书格式范文
2015/05/11 职场文书
张丽莉观后感
2015/06/16 职场文书
巴黎圣母院读书笔记
2015/06/26 职场文书
2016年学校综治宣传月活动总结
2016/03/16 职场文书
Vue自定义铃声提示音组件的实现
2022/01/22 Vue.js