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 相关文章推荐
简单三步,搞掂内存泄漏
Mar 10 Javascript
Javascript 垃圾收集机制介绍理解
May 14 Javascript
使用JavaScript获取电池状态的方法
May 03 Javascript
javascript中使用未定义变量或值的情况分析
Jul 19 Javascript
JS点击某个图标或按钮弹出文件选择框的实现代码
Sep 27 Javascript
js Canvas实现的日历时钟案例分享
Dec 25 Javascript
微信小程序 常见问题总结(4058,40013)及解决办法
Jan 11 Javascript
vue 2.1.3 实时显示当前时间,每秒更新的方法
Sep 16 Javascript
JS使用H5实现图片预览功能
Sep 30 Javascript
jquery使用echarts实现有向图可视化功能示例
Nov 25 jQuery
jquery实现进度条状态展示
Mar 26 jQuery
微信小程序入门之绘制时钟
Oct 22 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
用户的详细注册和判断
2006/10/09 PHP
在字符串指定位置插入一段字符串的php代码
2010/02/16 PHP
允许phpmyadmin空密码登录的配置方法
2011/05/29 PHP
PHP的PDO错误与错误处理
2019/01/27 PHP
PHP基于openssl实现非对称加密代码实例
2020/06/19 PHP
javawscript 三级菜单的实现原理
2009/07/01 Javascript
Prototype的Class.create函数解析
2011/09/22 Javascript
jquery判断浏览器类型的代码
2012/11/05 Javascript
file模式访问网页时iframe高度自适应解决方案
2013/01/16 Javascript
一个JavaScript变量声明的知识点
2013/10/28 Javascript
js动态设置div的值下例子
2013/10/29 Javascript
jQuery中[attribute^=value]选择器用法实例
2014/12/31 Javascript
js实现右下角提示框的方法
2015/02/03 Javascript
javascript实现的上下无缝滚动效果
2016/09/19 Javascript
详解JS中遍历语法的比较
2017/04/07 Javascript
bootstrap fileinput实现文件上传功能
2017/08/23 Javascript
说说AngularJS中的$parse和$eval的用法
2017/09/14 Javascript
Angular 开发学习之Angular CLI的安装使用
2017/12/31 Javascript
javascript中的闭包概念与用法实践分析
2019/07/26 Javascript
vue项目中openlayers绘制行政区划
2020/12/24 Vue.js
Python 基础之字符串string详解及实例
2017/04/01 Python
Python元组操作实例分析【创建、赋值、更新、删除等】
2017/07/24 Python
Python找出最小的K个数实例代码
2018/01/04 Python
pandas计数 value_counts()的使用
2019/06/24 Python
python实现大文本文件分割
2019/07/22 Python
django项目中使用手机号登录的实例代码
2019/08/15 Python
使用 tf.nn.dynamic_rnn 展开时间维度方式
2020/01/21 Python
在Ubuntu 20.04中安装Pycharm 2020.1的图文教程
2020/04/30 Python
pycharm 添加解释器的方法步骤
2020/08/31 Python
Anaconda使用IDLE的实现示例
2020/09/23 Python
CSS3 background-image颜色渐变的实现代码
2018/09/13 HTML / CSS
Vilebrequin欧洲官网:法国豪华泳装品牌(男士沙滩裤)
2018/04/14 全球购物
门诊手术室工作制度
2014/01/30 职场文书
基层党员群众路线整改措施及努力方向
2014/10/28 职场文书
css height属性中的calc方法详解
2021/06/03 HTML / CSS
SQL Server表分区降低运维和维护成本
2022/04/08 SQL Server