JavaScript中apply方法详解:参数传递与作用域绑定

作者:青柠

时间:2026-10-30

浏览:570

本文深入解析JavaScript中apply方法的两种核心用途:动态绑定函数执行时的this指向,以及处理可变数量参数的调用场景。通过对比直接赋值、call方法与ES5 bind方法,阐明apply在解耦对象与方法、实现优雅函数调用方面的优势,并附带兼容低版本浏览器的bind实现方案。

文章目录

apply()方法定义与核心作用

apply()方法定义

函数的apply()方法与call()方法功能一致,主要区别在于接收参数的方式不同。apply()方法接受两个参数:第一个是作为函数执行上下文的目标对象,第二个是包含实际参数的数组。

apply()作用

延长函数的作用域

1、用于延长函数的作用域

示例:


var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
sayColor();//"red"
sayColor.apply(o);//"blue" 

通过可以看出,利用apply()方法将函数动态绑定到了对象o上,此时this指向对象o,执行结果输出"blue"。

2、对象不需要与方法有任何耦合关系

下面通过一个耦合的例子,展示如何利用apply()方法解决这种紧密耦合问题。


var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
o.sayColor=sayColor;
o.sayColor();//"blue" 

如所示,先将函数赋值给对象o的一个属性,此时对象与方法紧密耦合,方法的调用必须通过对象o进行。

这种方式不如使用apply()或call()方法灵活。展示了重构后的代码,实现了更松散的调用方式。


var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
sayColor();//"red"
sayColor.apply(o);//"blue" 

如所示,对象并未绑定任何方法,而是在需要使用时,通过函数的apply或call方法动态绑定执行上下文。

对象和方法之间保持独立,没有耦合。展示了还可以通过ES5提供的bind()方法来完成类似功能。

实现可变参数函数传参

3、实现可变参数函数传参

下面是一个计算任意数量数字平均值的函数示例。


average(,,);
average();
average(,,,,,,,,);
average(,,,,,,,,,); 

average函数是一个可变参数函数(variadic function)的典型例子,函数的元数(arity)指其期望的参数个数。

当然,这个函数也可以设计为接收一个数组作为参数。


averageOfArray([,,]);
averageOfArray([]);
averageOfArray([,,,,,,,,]);
averageOfArray([,,,,,,,,,]); 

使用可变参数的函数代码更简洁、优雅。可变参数函数提供了便捷的语法,至少让调用者明确知道提供了多少个参数。

如果我有这样一个数组


var scores=getAllScores(); 

如何使用average函数计算平均值呢?

1.可变参数函数版本。

此时可以将average()方法与apply()配合使用。由于该函数未引用this变量,因此第一个参数传入null。展示了具体代码实现。


var scores=getAllScores();
average.apply(null,scores); 

2.直接参数为数组的形式

如所示,这里可以直接传入数组参数。


var scores=getAllScores();
averageOfArray(scores); 

以上两种形式均可,个人觉得第二种更简单。了解多种方法有助于在阅读他人代码时轻松应对,无需重构原有代码,这一优势更为显著。

实现可变参数方法的传值

4、实现可变参数方法的传值

示例:buffer对象包含一个可变参数的append方法,该方法将元素添加到函数内部的state数组中。


var buffer={
state:[],
append:function(){
for(var i=,n=arguments.length;i<n;i++){
this.state.push(arguments[i]);
}
}
}; 

此时append方法可以接受任意多个参数。


buffer.append('Hello,');
buffer.append('firtName',' ','lastName','!');
buffer.append('newLine'); 

形式如所示。


buffer.append(arg1,arg2,arg3,...) 

借助apply方法的this参数,我们可以指定一个可计算的数组来调用append方法。


buffer.append.apply(buffer,getInputStrings()); 

注意:中的buffer对象至关重要,如果传递不同的对象,append方法将尝试修改该错误对象的state属性。

提示

•使用apply方法指定一个可计算的参数数组来调用可变参数的函数 •使用apply方法的第一个参数给可变参数的方法提供一个接收者

附录一

average函数


function average(){
var args=[].slice.call(arguments);
var sum=args.reduce(function(prev,cur){
return prev+cur;
});
return parseInt(sum/args.length,);
} 

averageOfArray函数


function averageOfArray(arr){ 
var sum=arr.reduce(function(prev,cur){
return prev+cur;
});
return parseInt(sum/arr.length,);
} 

ES5 bind()方法与低版本兼容

ES5 bind()方法

这个方法创建一个函数的实例,其this值会被绑定到传给bind()函数的值。例如。


var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
var oSayColor=sayColor.bind(o);
oSayColor();//"blue" 

兼容低版本,参考使用下面的版本:


if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = [].slice.call(arguments, ),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP? this: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype; 
}
fBound.prototype = new fNOP();
return fBound;
};
} 

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章