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中 wrap() wrapAll() 与 wrapInner()的差异
Nov 12 Javascript
JavaScript中join()方法的使用简介
Jun 09 Javascript
javascript实现动态导入js与css等静态资源文件的方法
Jul 25 Javascript
jQuery 如何给Carousel插件添加新的功能
Apr 18 Javascript
js添加事件的通用方法推荐
May 15 Javascript
使用Promise解决多层异步调用的简单学习心得
May 17 Javascript
jQuery设置聚焦并使光标位置在文字最后的实现方法
Aug 02 Javascript
纯js实现手风琴效果代码
Apr 17 Javascript
详解基于node的前端项目编译时内存溢出问题
Aug 01 Javascript
jQuery:unbind方法的使用详解
Aug 14 jQuery
Vue 3.0中jsx语法的使用
Nov 13 Javascript
Vue使用Ref跨层级获取组件的步骤
Jan 25 Vue.js
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产生随机字符串函数
2006/12/06 PHP
利用PHP实现短域名互转
2013/07/05 PHP
php输出含有“#”字符串的方法
2017/01/18 PHP
php利用ob_start()清除输出和选择性输出的方法
2018/01/18 PHP
Javascript 的addEventListener()及attachEvent()区别分析
2009/05/21 Javascript
基于Unit PNG Fix.js有时候在ie6下不正常的解决办法
2013/06/26 Javascript
Js获取数组最大和最小值示例代码
2013/10/29 Javascript
基于javascript实现tab切换特效
2016/03/29 Javascript
详解获取jq ul第一个li定位的四种解决方案
2016/11/23 Javascript
原生js实现弹出层效果
2017/01/20 Javascript
node.js中实现kindEditor图片上传功能的方法教程
2017/04/26 Javascript
Bootstrap Table 搜索框和查询功能
2017/11/30 Javascript
Vue中"This dependency was not found"问题的解决方法
2018/06/19 Javascript
详解如何在微信小程序中愉快地使用sass
2018/07/30 Javascript
使用Angular material主题定义自己的组件库的配色体系
2019/09/04 Javascript
JS实现简单省市二级联动
2019/11/27 Javascript
原生js实现瀑布流效果
2020/03/09 Javascript
jquery实现轮播图特效
2020/04/12 jQuery
JavaScript冒泡算法原理与实现方法深入理解
2020/06/04 Javascript
Vue自定义多选组件使用详解
2020/09/08 Javascript
JS绘图Flot如何实现可选显示曲线图功能
2020/10/16 Javascript
Python字符串拼接六种方法介绍
2017/12/18 Python
python中cPickle类使用方法详解
2018/08/27 Python
判断python对象是否可调用的三种方式及其区别详解
2019/01/31 Python
Python实现时间序列可视化的方法
2019/08/06 Python
python实现拼图小游戏
2020/02/22 Python
mac 上配置Pycharm连接远程服务器并实现使用远程服务器Python解释器的方法
2020/03/19 Python
AmazeUI中模态框的实现
2020/08/19 HTML / CSS
BLACKMORES澳洲官网:澳大利亚排名第一的保健品牌
2018/09/27 全球购物
八皇后问题,输出了所有情况,不过有些结果只是旋转了90度
2016/08/15 面试题
大四学生毕业自荐信
2013/11/07 职场文书
十佳大学生村官事迹
2014/01/09 职场文书
医院学雷锋活动策划方案
2014/02/15 职场文书
面试感谢信范文
2015/01/22 职场文书
家属慰问信
2015/02/14 职场文书
MySQL8.0.18配置多主一从
2021/06/21 MySQL