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 相关文章推荐
php gethostbyname获取域名ip地址函数详解
Jan 24 Javascript
js操作iframe父子窗体示例
May 22 Javascript
兼容主流浏览器的JS复制内容到剪贴板
Dec 12 Javascript
JavaScript中的包装对象介绍
Jan 27 Javascript
Javascript实现检测客户端类型代码封包
Dec 03 Javascript
JavaScript实现DOM对象选择器
Sep 24 Javascript
JavaScript中常用的验证reg
Oct 13 Javascript
jquery append与appendTo方法比较
May 24 jQuery
javaScript封装的各种写法
Aug 14 Javascript
webpack4.x CommonJS模块化浅析
Nov 09 Javascript
微信小程序商品详情页底部弹出框
Nov 22 Javascript
JavaScript队列结构Queue实现过程解析
Mar 07 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
ThinkPHP使用smarty模板引擎的方法
2014/07/01 PHP
php+ajax实现商品对比功能示例
2019/04/13 PHP
如何利用PHP实现上传图片功能详解
2020/09/24 PHP
JQuery实现自定义对话框的代码
2008/06/15 Javascript
JavaScript操作XML 使用百度RSS作为新闻源示例
2012/02/17 Javascript
一个简单的网站访问JS计数器 刷新1次加1次访问
2012/09/20 Javascript
JS实现div居中示例
2014/04/17 Javascript
在linux中使用包管理器安装node.js
2015/03/13 Javascript
基于Javascript倒计时效果
2016/12/22 Javascript
elemetUi 组件--el-upload实现上传Excel文件的实例
2017/10/27 Javascript
最简单的JS实现json转csv的方法
2019/01/10 Javascript
详解vue配置后台接口方式
2019/03/29 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
vue 验证码界面实现点击后标灰并设置div按钮不可点击状态
2019/10/28 Javascript
Vue中使用matomo进行访问流量统计的实现
2019/11/05 Javascript
js实现验证码干扰(静态)
2021/02/22 Javascript
Python学习资料
2007/02/08 Python
Python实现基本数据结构中栈的操作示例
2017/12/04 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
解决Python发送Http请求时,中文乱码的问题
2020/04/30 Python
基于python实现查询ip地址来源
2020/06/02 Python
HTML5 Canvas 起步(1) - 基本概念
2009/05/12 HTML / CSS
美国礼品卡商城: Gift Card Mall
2017/08/25 全球购物
英国领先的体验日提供商:Buyagift
2019/04/19 全球购物
马来西亚在线药房:RoyalePharma
2019/12/01 全球购物
公积金转移接收函
2014/01/11 职场文书
全神贯注教学反思
2014/02/03 职场文书
安全生产月演讲稿
2014/05/09 职场文书
竞聘演讲稿开场白
2014/08/25 职场文书
庐山导游词
2015/02/03 职场文书
淘宝文案策划岗位职责
2015/04/14 职场文书
2015年度对口支援工作总结
2015/07/22 职场文书
学习委员竞选稿
2015/11/20 职场文书
入团申请书格式
2019/06/20 职场文书
原来闭幕词是这样写的呀!
2019/07/01 职场文书
自己搭建resnet18网络并加载torchvision自带权重的操作
2021/05/13 Python