JavaScript中每个函数都包含两个非继承而来的方法:apply()和call()
下面是apply()和call()的定义及语法:
/*
* apply()方法
* 定义:应用某一个对象的一个方法,以另一个对象替换当前对象
**/
apply(this,arguments);
apply(this,[arg1,arg2,...]);
/*
* call()方法
* 定义:应用某一个对象的一个方法,以另一个对象替换当前对象
**/
call(this,arg1,arg2,...);
可以看出两者的作用是相同的,简单来讲,这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。首先他们接收到的第一个参数都是运行函数的作用域,其余的参数是参数数组。对apply()来讲,第二个参数可以是Apply的实例,也可以是arguments对象;而对call()来讲,除第一个参数外,其余的参数都直接传递给函数,换句话说,使用call()方法时传递给函数的参数必须逐个列举出来。
下面举个例子:
function sum(num1,num2){
return num1+num2;
}
function applySum1(num1,num2){
return sum.apply(this,[num1,num2]);
}
function applySum2(num1,num2){
return sum.apply(this,arguments);
}
console.log("applySum1="+applySum1(10,30));
console.log("applySum2="+applySum2(10,30));
function callSum(num1,num2){
return sum.call(this,num1,num2);
}
console.log("callSum="+callSum(10,30));
运行结果:
在上面的例子中,applySum1()在执行sum()函数时传入了this作为this值(因为是在全局作用域中调用的,所以传入的就是window对象)和一个参数数组。同样applySum2()也调用了sum()函数,但是他传入的是this和arguments对象。两个函数都正常执行并且返回结果。
在使用call()的情况下,callSum()必须明确的传入每一个参数,返回结果与apply()相同。
那么问题来了,apply()和call()什么什么情况下使用好呢?这个取决于你采取哪种参数传递方式,如果打算直接传入arguments对象或者包含函数中先接收到的也是一个数组,那么使用apply()比较方便;否则,选择call()可能更合适;如果不需要传递参数,则两者都可以。
事实上,apply()和call()更强大的地方是能够扩充函数赖以运行的作用域。
例如:
window.test = "global";
var obj = {test:"local"};
function checkTest(){
alert(this.test);
}
checkTest(); //global
checkTest.call(this); //global
checkTest.call(window); //global
checkTest.call(obj); //local
上面示例中checkTest是作为全局函数定义的,当在全局作用域中调用它时,会显示global,因为对this.test的求值会转换成window.test。而checkTest.call(this)和checkTest.call(window) ,则是显示的在全局作用域中调用函数的方式,当然会显示global。但是当运行checkTest.call(obj)时,函数的执行环境就不一样了,此时函数体内的this对象指向了obj。
使用apply()和call()来扩充作用域的最大好处,就是对象不需要与方法有任何的耦合关系。