代码的魅力

BI, .NET
posts - 24, comments - 0, trackbacks - 0, articles - 0

导航

Javascript中的apply和call函数

Posted on 2009-03-01 19:45  moge  阅读(...)  评论(...编辑  收藏
通过一个例子说明apply()的用法:
//针对各种浏览器建立一个http request的对象

function getHttpRequest(){
   http_request = null;
   if (window.XMLHttpRequest) {

      http_request = new XMLHttpRequest();
   } else if (window.ActiveXObject) {
       http_request = new ActiveXObject("Microsoft.XMLHTTP");
   }
   return http_request;
}

var ajax_request;

functiong getPerson(){

ajax_request = getHttpRequest();    //建立一个http request

ajax_request.onstatechange = handleResponse; //指定回调函数

ajax_request.open("GET", "http://myhost.com/sample.xml", null);

ajax_request.send();

}


function handleResponse(){

if(ajax_request.readyState != 4) return;

if(ajax_request.status == 200){

    var xml = ajax_request.responseXML;

    /* 对获得的xml的处理 */

}

}


调用的时候可以直接在页面里调用

getPerson();


这个函数会建立一个httpRequest对象,然后发送请求,在请求返回的时候会自动调用handleResponse函数来完成操作。

在简单的环境上,上述代码会工作得很好,但是如果在一个页面中要执行多次这种操作就比较麻烦了,需要写多个函数,看一下上面的定义:

var ajax_request; 表示这是个全局变量,多次请求的时候每个请求都要用到这个对象,ajax又是异步的,无法事先确定哪个请求先返回。


如果把ajax_request作为函数内的局部变量呢?那样如果在handleResponse里能看到ajax_request对象就可以解决这个问题了。

可以考虑把ajax_request作为一个参数传递给handleResponse,现在的问题是,对handleResponse的调用是自动的,怎么能在参数列表中添加这个参数呢?我们想到了this变量,在javascript中,所有的东西都是对象,this表示当前对象,在函数中this就表示当前的函数。

javascript提供了一种可以改变this的方法——apply()。

javascript对apply的解释是:使用指定对象替换当前对象并调用函数。比如:


function test_apply(){

alert(this);

}

test_apply.apply(document, []);


就表示调用函数test_apply,并用document对象来替换test_apply中的this。


回到刚刚的问题,为了修改当前对象,需要在指定handleResponse的时候就修改this对象。ajax_request.onstatechange是一个函数的句柄,只要我把一个函数的句柄赋值给它就可以了,同时函数也是一种对象,Function对象,因此我们为函数对象添加一个方法:

Function.prototype.setThis(){

var curr_function = this;

var to_this_object = arguments[0];

return function(){

    currFunc.apply(to_this_object, []);

};

}


下面,修改getPerson为:


functiong getPerson(){

var tmp_request = getHttpRequest();    //建立一个http request

tmp_request.onstatechange = handleResponse.setThis(tmp_request); //指定回调函数

tmp_request.open("GET", "http://myhost.com/sample.xml", null);

tmp_request.send();

}


修改handleResponse为:


function handleResponse(){

if(this.readyState != 4) return;

if(this.status == 200){

    var xml = this.responseXML;

    /* 对获得的xml的处理 */

}

}

即可。

具体的变化就在于tmp_request.onstatechange = handleResponse.setThis(tmp_request);

因为handleResponse是一个函数,因此它具有Function新添加的方法setThis,

下面来看setThis方法:

var curr_function = this; //获得当前的函数本身
var to_this_object = arguments[0]; //获得要指定的新的this对象

return function(){

    currFunc.apply(to_this_object, []);

};


这里的返回值是一个函数,即当tmp_request的onstatechange事件的时候会触发这个函数,该函数中只有一句

currFunc.apply(to_this_object, []);即用to_this_object替换当前对象并调用currFunc,在这里currFunc即代表了handleResponse,因此调用handleResponse,因为已经修改了其this对象,因此在handleResponse中用this即代表了tmp_request对象。

用这种方法可以减化代码,并使代码更具可重用性。
源文地址:http://www.cublog.cn/opera/showart.php?blogid=21787&id=140549

附注:

应用某一对象的一个方法,用另一个对象替换当前对象。


apply([thisObj[,argArray]])参数thisObj可选项。将被用作当前对象的对象。

argArray

可选项。将被传递给该函数的参数数组。

说明

如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

javascript apply()方法二

官方解释:应用某一对象的一个方法,用另一个对象替换当前对象。

apply与call的区别是第二个参数不同。apply是 数组或者arguments 对象。而call是逗号隔开的任何类型。

<html>
<body>
<div>test</div>
<input id="input" type=button value='click' onclick="c()" class="aa"/>
<script>


function test_apply()

    alert(this.value + " " + arguments[0] + " " + arguments[1]);
}
test_apply.call(document.getElementById("input"),'aa',1);
test_apply.apply(document.getElementById("input"),['aa','1']);

</script>
</body>
</html>