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 相关文章推荐
jQuery EasyUI API 中文文档 - PropertyGrid属性表格
Nov 18 Javascript
SinaEditor使用方法详解
Dec 28 Javascript
详谈JavaScript 匿名函数及闭包
Nov 14 Javascript
jquery实现从数组移除指定的值
Jun 24 Javascript
js事件处理程序跨浏览器解决方案
Mar 27 Javascript
JS 组件系列之BootstrapTable的treegrid功能
Jun 16 Javascript
vue-resource + json-server模拟数据的方法
Nov 02 Javascript
js将键值对字符串转为json字符串的方法
Mar 30 Javascript
详解小程序开发经验:多页面数据同步
May 18 Javascript
原生JS使用Canvas实现拖拽式绘图功能
Jun 05 Javascript
js实现简单的日历显示效果函数示例
Nov 25 Javascript
微信小程序实现聊天室
Aug 21 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
php桌面中心(一) 创建数据库
2007/03/11 PHP
PHP UTF8编码内的繁简转换类
2009/07/20 PHP
PHP中绘制图像的一些函数总结
2014/11/19 PHP
分享php分页的功能模块
2015/06/16 PHP
php 算法之实现相对路径的实例
2017/10/17 PHP
tp5.1 框架查询表达式用法详解
2020/05/25 PHP
基于prototype的validation.js发布2.3.4新版本,让你彻底脱离表单验证的烦恼
2006/12/06 Javascript
Javascript基础教程之数据类型 (数值 Number)
2015/01/18 Javascript
Javascript操作表单实例讲解(下)
2016/06/20 Javascript
javascript实现圣旨卷轴展开效果(代码分享)
2017/03/23 Javascript
React学习笔记之事件处理(二)
2017/07/02 Javascript
利用require.js与angular搭建spa应用的方法实例
2017/07/19 Javascript
详解Vue的钩子函数(路由导航守卫、keep-alive、生命周期钩子)
2018/07/24 Javascript
微信小程序在其他页面监听globalData中值的变化
2019/07/15 Javascript
Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制
2019/09/05 Javascript
浅谈vue项目用到的mock数据接口的两种方式
2019/10/09 Javascript
python将文本转换成图片输出的方法
2015/04/28 Python
Python程序中用csv模块来操作csv文件的基本使用教程
2016/03/03 Python
python一键升级所有pip package的方法
2017/01/16 Python
python 判断网络连通的实现方法
2018/04/22 Python
python十进制和二进制的转换方法(含浮点数)
2018/07/07 Python
python实现C4.5决策树算法
2018/08/29 Python
Python 调用 zabbix api的方法示例
2019/01/06 Python
使用PIL(Python-Imaging)反转图像的颜色方法
2019/01/24 Python
Django Rest framework认证组件详细用法
2019/07/25 Python
Python开发之基于模板匹配的信用卡数字识别功能
2020/01/13 Python
python图片剪裁代码(图片按四个点坐标剪裁)
2020/03/10 Python
浅谈django不使用restframework自定义接口与使用的区别
2020/07/15 Python
Python 实现一个简单的web服务器
2021/01/03 Python
英国设计师泳装、沙滩装和比基尼在线精品店:Beach Cafe
2019/08/28 全球购物
简述进程的启动、终止的方式以及如何进行进程的查看
2013/07/12 面试题
毕业生个人求职自荐信
2014/02/26 职场文书
2014年出纳工作总结与计划
2014/12/09 职场文书
房产公证书格式
2015/01/26 职场文书
鲁迅故里导游词
2015/02/05 职场文书
SpringBoot+Redis实现布隆过滤器的示例代码
2022/03/17 Java/Android