jQuery AJAX回调函数this指向问题

了解JavaScript的人都知道JavaScript的this不总是指向当前对象,函数或类中的this指向与调用这个函数的对象以及上下文环境是息息相关的。如在全局作用域调用一个含this的对象,此时当前对象的this指向的是window。为了让this的指向符合自己的意愿,JavaScript提供了两个方法用以改变this的指向,它们是callapply,当然也有利用闭包来实现的方法。本文通过一个例子来说明这些问题。

先看一段演示代码,这代码只供演示用,没有实际意义。

// 一个没有实际意义的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)});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值