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在IE和Firefox浏览器下的7个差异兼容写法小结
Jun 18 Javascript
js getBoundingClientRect() 来获取页面元素的位置
Nov 25 Javascript
Javascript获取窗口(容器)的大小及位置参数列举及简要说明
Dec 09 Javascript
js实现点击注册按钮开始读秒倒计时的小例子
May 11 Javascript
Vue.js中用webpack合并打包多个组件并实现按需加载
Feb 17 Javascript
jquery实现全选、全不选以及单选功能
Mar 23 jQuery
详解react-router如何实现按需加载
Jun 15 Javascript
Popup弹出框添加数据实现方法
Oct 27 Javascript
JS使用tween.js动画库实现轮播图并且有切换功能
Jul 17 Javascript
基于axios 解决跨域cookie丢失的问题
Sep 26 Javascript
微信小程序实现卡片层叠滑动效果
Jun 21 Javascript
JavaScript写个贪吃蛇小游戏(超详细)
Mar 17 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
2020年4月放送决定!第2期TV动画《邪神酱飞踢》视觉图&主题曲情报公开!
2020/03/06 日漫
星际争霸 Starcraft 游戏介绍
2020/03/14 星际争霸
基于php伪静态的实现详细介绍
2013/04/28 PHP
PHP中HTML标签过滤技巧
2014/01/07 PHP
destoon二次开发入门示例
2014/06/20 PHP
php通过获取头信息判断图片类型的方法
2015/06/26 PHP
php基于dom实现的图书xml格式数据示例
2017/02/03 PHP
PHP设计模式之数据访问对象模式(DAO)原理与用法实例分析
2019/12/12 PHP
简单的无缝滚动程序-仅几行代码
2007/05/08 Javascript
Javascript 错误处理的几种方法
2009/06/13 Javascript
jQuery Ajax 仿AjaxPro.Utility.RegisterTypeForAjax辅助方法
2011/09/27 Javascript
js的压缩及jquery压缩探讨(提高页面加载性能/保护劳动成果)
2013/01/29 Javascript
node.js中的fs.createReadStream方法使用说明
2014/12/17 Javascript
JavaScript 里的类数组对象
2015/04/08 Javascript
Bootstrap的图片轮播示例代码
2015/08/31 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
jquery二级目录选中当前页的css样式
2016/12/08 Javascript
JS返回只包含数字类型的数组实例分析
2016/12/16 Javascript
js简单实现网页换肤功能
2017/04/07 Javascript
在React中如何优雅的处理事件响应详解
2017/07/24 Javascript
基于 Vue 实现一个酷炫的 menu插件
2017/11/14 Javascript
解决nodejs的npm命令无反应的问题
2018/05/17 NodeJs
vue 内置过滤器的使用总结(附加自定义过滤器)
2018/12/11 Javascript
JavaScript中0、空字符串、'0'是true还是false的知识点分享
2019/09/16 Javascript
基于PHP pthreads实现多线程代码实例
2020/06/24 Javascript
Python3中常用的处理时间和实现定时任务的方法的介绍
2015/04/07 Python
python文件的md5加密方法
2016/04/06 Python
python3+PyQt5使用数据库窗口视图
2018/04/24 Python
python SOCKET编程基础入门
2021/02/27 Python
水上运动奥特莱斯:Wasterports Outlet
2018/08/08 全球购物
美国中西部家用医疗设备商店:Med Mart(轮椅、踏板车、升降机等)
2019/04/26 全球购物
2015年三万活动总结
2015/03/25 职场文书
2015年员工试用期工作总结
2015/05/28 职场文书
幽灵公主观后感
2015/06/09 职场文书
Requests什么的通通爬不了的Python超强反爬虫方案!
2021/05/20 Python
Python自动化爬取天眼查数据的实现
2021/06/15 Python