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 相关文章推荐
前端开发部分总结[兼容性、DOM操作、跨域等](持续更新)
Mar 04 Javascript
jQuery实现切换页面布局使用介绍
Oct 09 Javascript
利用webqq协议使用python登录qq发消息源码参考
Apr 08 Javascript
如何使用jQuery来处理图片坏链具体实现步骤
May 02 Javascript
浅析JQuery获取和设置Select选项的常用方法总结
Jul 04 Javascript
jQuery jcrop插件截图使用方法
Nov 20 Javascript
使用documentElement正确取得当前可见区域的大小
Jul 25 Javascript
原生javascript实现Tab选项卡切换功能
Jan 12 Javascript
jQuery焦点控制图层展示延迟隐藏的方法
Mar 09 Javascript
JavaScript实现文本框中默认显示背景图片在获得焦点后消失的方法
Jul 01 Javascript
AngularJS实现的获取焦点及失去焦点时的表单验证功能示例
Oct 25 Javascript
在vue中获取token,并将token写进header的方法
Sep 26 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
虫族 Zerg 历史背景
2020/03/14 星际争霸
php动态生成JavaScript代码
2009/03/09 PHP
php页面缓存ob系列函数介绍
2012/10/18 PHP
PHP面向对象之旅:深入理解static变量与方法
2014/01/06 PHP
php使用fgetcsv读取csv文件出现乱码的解决方法
2014/11/08 PHP
php实现无限级分类(递归方法)
2015/08/06 PHP
Prototype Array对象 学习
2009/07/19 Javascript
推荐8款jQuery轻量级树形Tree插件
2014/11/12 Javascript
jQuery关键词说明插件cluetip使用指南
2015/04/21 Javascript
JS组件Bootstrap Select2使用方法解析
2016/05/30 Javascript
Javascript封装id、class与元素选择器方法示例
2017/03/13 Javascript
用js实现每隔一秒刷新时间的实例(含年月日时分秒)
2017/10/25 Javascript
利用JS测试目标网站的打开响应速度
2017/12/01 Javascript
浅谈Webpack自动化构建实践指南
2017/12/18 Javascript
微信小程序中使用ECharts 异步加载数据的方法
2018/06/27 Javascript
详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)
2020/07/21 Javascript
解决vue页面刷新,数据丢失的问题
2020/11/24 Vue.js
python3.x上post发送json数据
2018/03/04 Python
pandas表连接 索引上的合并方法
2018/06/08 Python
Python解决线性代数问题之矩阵的初等变换方法
2018/12/12 Python
django xadmin中form_layout添加字段显示方式
2020/03/30 Python
完美解决Django2.0中models下的ForeignKey()问题
2020/05/19 Python
基于PyTorch的permute和reshape/view的区别介绍
2020/06/18 Python
在CentOS7下安装Python3教程解析
2020/07/09 Python
scrapy redis配置文件setting参数详解
2020/11/18 Python
一款CSS3实现多功能下拉菜单(带分享按)的教程
2014/11/05 HTML / CSS
HTML5 drag和drop具体使用详解
2021/01/18 HTML / CSS
瑞典手机壳品牌:Richmond & Finch
2018/04/28 全球购物
世界各地的当地人的食物体验:Eatwith
2019/07/26 全球购物
阳光体育活动总结
2014/04/30 职场文书
法院四风对照检查材料思想汇报
2014/10/06 职场文书
2014年幼儿园个人工作总结
2014/11/10 职场文书
2015会计试用期工作总结
2014/12/12 职场文书
入伍通知书
2015/04/23 职场文书
团支部书记竞选稿
2015/11/21 职场文书
Python实现天气查询软件
2021/06/07 Python