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实现的一个导航滚动效果具体代码
May 27 Javascript
javascript通过navigator.userAgent识别各种浏览器
Oct 25 Javascript
Jquery $.getJSON 在IE下的缓存问题解决方法
Oct 10 Javascript
解析JavaScript面向对象概念中的Object类型与作用域
May 10 Javascript
使用vue + less 实现简单换肤功能的示例
Feb 21 Javascript
Vue filter介绍及详细使用
Apr 04 Javascript
详解Puppeteer 入门教程
May 09 Javascript
在vue项目中正确使用iconfont的方法
Sep 28 Javascript
npm scripts 使用指南详解
Oct 08 Javascript
vue总线机制(bus)知识点详解
May 10 Javascript
JavaScript设计模式---单例模式详解【四种基本形式】
May 16 Javascript
JS寄快递地址智能解析的实现代码
Jul 16 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与javascript的两种交互方式
2006/10/09 PHP
php对称加密算法示例
2014/05/07 PHP
深入php内核之php in array
2015/11/10 PHP
PHP5.6读写excel表格文件操作示例
2019/02/26 PHP
浅谈PHP array_search 和 in_array 函数效率问题
2019/10/15 PHP
javascript变量作用域使用中常见错误总结
2013/03/26 Javascript
node.js使用nodemailer发送邮件实例
2014/03/10 Javascript
jQuery中的$.ajax()方法应用
2014/05/06 Javascript
js/jquery判断浏览器的方法小结
2014/09/02 Javascript
简介JavaScript中POSITIVE_INFINITY值的使用
2015/06/05 Javascript
jquery.validate.js 多个相同name的处理方式
2017/07/10 jQuery
React Native react-navigation 导航使用详解
2017/12/01 Javascript
JS匿名函数内部this指向问题详析
2019/05/10 Javascript
React中使用外部样式的3种方式(小结)
2019/05/28 Javascript
基于JS正则表达式实现模板数据动态渲染(实现思路详解)
2020/03/07 Javascript
[48:30]LGD vs infamous Supermajor小组赛D组 BO3 第一场 6.3
2018/06/04 DOTA
python 中文乱码问题深入分析
2011/03/13 Python
python使用PyFetion来发送短信的例子
2014/04/22 Python
Python中用format函数格式化字符串的用法
2015/04/08 Python
Python yield 使用浅析
2015/05/28 Python
Python循环语句中else的用法总结
2016/09/11 Python
Python网络爬虫与信息提取(实例讲解)
2017/08/29 Python
python自动查询12306余票并发送邮箱提醒脚本
2018/05/21 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
python之线程通过信号pyqtSignal刷新ui的方法
2019/01/11 Python
使用TensorFlow实现二分类的方法示例
2019/02/05 Python
详解pandas使用drop_duplicates去除DataFrame重复项参数
2019/08/01 Python
使用postMessage让 iframe自适应高度的方法示例
2019/10/08 HTML / CSS
Clearly新西兰:购买眼镜、太阳镜和隐形眼镜
2018/04/26 全球购物
女方婚礼新郎答谢词
2014/01/11 职场文书
法律系毕业生自荐信范文
2014/03/27 职场文书
推荐信模板
2014/05/09 职场文书
全国优秀辅导员事迹材料
2014/05/14 职场文书
企业员工辞职信范文
2015/05/12 职场文书
Python实现位图分割的效果
2021/11/20 Python
Python+DeOldify实现老照片上色功能
2022/06/21 Python