javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript apply 方法

JavaScript apply 方法示例详解

作者:Peter-Lu

本文详解JavaScript中apply方法,作为函数三兄弟之一,用于显式绑定this上下文,其语法通过数组传递参数,适用于回调、方法复用、数组处理及继承场景,与call、bind区别在于参数形式及是否立即调用,ES6扩展运算符提供替代方案,感兴趣的朋友一起看看吧

在 JavaScript 中,apply 是函数对象(Function)自带的一个非常重要的方法,与 callbind 并称为“函数三兄弟”。它们都属于函数的“显式调用”方式,常用于动态改变函数的执行上下文(this 指向)。本文将带你全面理解 apply 的语法、作用机制、实际应用场景,以及与 callbind 的区别,帮助你在开发中灵活运用它提升代码的复用性与灵活性。

一、函数是“对象”,apply 是“方法”

在 JavaScript 中,函数是一等公民(First-Class Object),这意味着函数本质上是对象,具备一些自带的方法,例如 applycallbind 等。

apply 是定义在 Function.prototype 上的方法,任何函数都可以通过继承使用它。

换句话说:

typeof Function.prototype.apply === 'function' // true

二、apply 的基本语法

func.apply(thisArg, [argsArray])

参数说明:

示例:

function greet(language1, language2) {
  console.log(`${this.name} 会说 ${language1} 和 ${language2}`);
}
const person = { name: '小明' };
greet.apply(person, ['中文', '英文']);
// 输出:小明 会说 中文 和 英文

在这个例子中,greet 原本的 this 是 undefined,但我们通过 applythis 显式绑定到了 person 对象上。

三、apply 与 call、bind 的区别

虽然 applycallbind 都可以显式地设置函数的执行上下文,但三者的用法略有不同:

方法名是否立即调用参数形式
call依次传入参数(逗号分隔)
apply参数打包成一个数组
bind否(返回新函数)依次传入参数(逗号分隔)

示例对比:

function sayHello(a, b) {
  console.log(`${this.name}:${a} + ${b}`);
}
const obj = { name: '小红' };
// call
sayHello.call(obj, '早上好', '下午好');
// apply
sayHello.apply(obj, ['早上好', '下午好']);
// bind
const newFunc = sayHello.bind(obj, '早上好', '下午好');
newFunc(); // 手动调用

四、apply 的核心用途场景

1. 改变函数的 this 指向

这是最常见的用法之一,尤其在一些回调函数或事件处理函数中使用 apply 来设置上下文环境。

function introduce(age) {
  console.log(`我是 ${this.name},今年 ${age} 岁`);
}
const student = { name: '小李' };
introduce.apply(student, [20]); // 输出:我是 小李,今年 20 岁

2. 借用其他对象的方法(函数借用)

apply 非常适合用来实现“对象之间的方法复用”,这在类数组对象处理时特别常见。

例如,类数组转真正数组:

function toArray() {
  return Array.prototype.slice.apply(arguments);
}
console.log(toArray(1, 2, 3)); // [1, 2, 3]

3. 获取数组中的最大值或最小值

在不知道数组长度的情况下,apply 可以把数组“拆开”传给 Math.maxMath.min

const arr = [5, 1, 99, 34];
const max = Math.max.apply(null, arr); // 99
const min = Math.min.apply(null, arr); // 1

如果你用 Math.max(arr) 是不行的,会返回 NaN。

4. 在构造函数中实现继承(经典继承)

在 ES6 之前,apply 是构造函数继承的一种常见方案。

function Animal(name) {
  this.name = name;
}
function Dog(name, breed) {
  Animal.apply(this, [name]); // 继承 Animal 的属性
  this.breed = breed;
}
const dog = new Dog('旺财', '柴犬');
console.log(dog.name); // 旺财
console.log(dog.breed); // 柴犬

通过 Animal.apply(this, [name]),将 Animal 构造函数中的属性“复制”到 Dog 的实例上。

5. 配合 arguments 实现通用封装

由于 arguments 是一个类数组对象,很多时候我们需要将其传递给另一个函数,而 apply 可以直接帮我们完成这一操作:

function wrapperFunction() {
  return targetFunction.apply(this, arguments);
}

这在写代理、装饰器函数(decorator)时尤其有用。

五、深入理解参数数组

apply 的第二个参数必须是一个数组或类数组对象(例如 argumentsNodeListHTMLCollection)。

错误示例:

func.apply(thisArg, 'not an array') // ❌ 报错:CreateListFromArrayLike called on non-object

正确示例:

func.apply(thisArg, ['a', 'b']) // ✅
func.apply(thisArg, arguments)  // ✅

六、ES6 的替代方案:扩展运算符

虽然 apply 非常强大,但在 ES6 之后,... 扩展运算符提供了更优雅的替代写法。

示例:

Math.max(...arr); // 替代 Math.max.apply(null, arr)
func(...args);    // 替代 func.apply(thisArg, args)

所以,现代开发中,如果没有必要改变 this 的话,推荐使用扩展运算符。

七、注意事项与陷阱

1. 严格模式下 this 不自动转为对象

在非严格模式中,如果传入 null 或 undefined,apply 会默认将 this 转为全局对象(浏览器中为 window)。

但在严格模式中,thisArg 保持原样:

'use strict';
function test() {
  console.log(this); // null
}
test.apply(null);

2. 参数数量限制问题

在某些老旧的 JavaScript 引擎中(如 IE),apply 所支持的参数数组长度是有限的,如果数组太大(例如上万项)可能会报错。解决办法是使用循环或改用 forEach 等方法处理。

八、真实项目中的使用建议

到此这篇关于JavaScript apply 方法示例详解的文章就介绍到这了,更多相关JavaScript apply 方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文