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 相关文章推荐
如何判断图片地址是否失效
Feb 02 Javascript
动态添加js事件实现代码
Mar 12 Javascript
javascript 处理事件绑定的一些兼容写法
Dec 24 Javascript
浅析jquery某一元素重复绑定的问题
Jan 03 Javascript
javascript遍历控件实例详细解析
Jan 10 Javascript
jquery处理页面弹出层查询数据等待操作实例
Mar 25 Javascript
基于OL2实现百度地图ABCD marker的效果
Oct 01 Javascript
获取JS中网页各种高宽与位置的方法总结
Jul 27 Javascript
layui 设置table 行的高度方法
Aug 17 Javascript
微信小程序 多行文本显示...+显示更多按钮和收起更多按钮功能
Sep 26 Javascript
JavaScript装饰者模式原理与用法实例详解
Mar 09 Javascript
vue 使用rules对表单字段进行校验的步骤
Dec 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企业级应用之常见缓存技术篇
2011/01/27 PHP
设置php页面编码的两种方法示例介绍
2014/03/03 PHP
php将csv文件导入到mysql数据库的方法
2014/12/24 PHP
PHP的Yii框架中Model模型的学习教程
2016/03/29 PHP
浅谈PHP SHA1withRSA加密生成签名及验签
2019/03/18 PHP
基于PHP+mysql实现新闻发布系统的开发
2020/08/06 PHP
top.location.href 没有权限 解决方法
2008/08/05 Javascript
jquery实现图片裁剪思路及实现
2013/08/16 Javascript
JQuery的ready函数与JS的onload的区别详解
2013/11/21 Javascript
使用CSS样式position:fixed水平滚动的方法
2014/02/19 Javascript
js模仿java的Map集合详解
2016/01/06 Javascript
js 动态生成json对象、时时更新json对象的方法
2016/12/02 Javascript
Angular2 PrimeNG分页模块学习
2017/01/14 Javascript
element ui里dialog关闭后清除验证条件方法
2018/02/26 Javascript
JavaScript实现百度搜索框效果
2020/03/26 Javascript
Element UI框架中巧用树选择器的实现
2018/12/12 Javascript
JQuery获取可视区尺寸和文档尺寸及制作悬浮菜单示例
2019/05/14 jQuery
vue实现放大镜效果
2020/09/17 Javascript
python处理中文编码和判断编码示例
2014/02/26 Python
Python多线程编程(六):可重入锁RLock
2015/04/05 Python
详解python如何在django中为用户模型添加自定义权限
2018/10/15 Python
python实现嵌套列表平铺的两种方法
2018/11/08 Python
CSS3弹性盒模型开发笔记(一)
2016/04/26 HTML / CSS
HTML5 placeholder(空白提示)属性介绍
2013/08/07 HTML / CSS
澳大利亚购买太阳镜和眼镜网站:Glamoureyes
2020/09/22 全球购物
中国梦的演讲稿
2014/01/08 职场文书
商务会议邀请函
2014/01/09 职场文书
我的大学生活演讲稿
2014/04/25 职场文书
党员个人对照检查材料范文
2014/09/24 职场文书
房屋买卖协议书范本
2014/09/27 职场文书
政风行风评议心得体会
2014/10/21 职场文书
先进个人申报材料
2014/12/30 职场文书
2016元旦主持人开场白
2015/12/03 职场文书
Pytorch 如何实现常用正则化
2021/05/27 Python
MySQL 8.0 驱动与阿里druid版本兼容问题解决
2021/07/01 MySQL
MySQL数据库⾼可⽤HA实现小结
2022/01/22 MySQL