Function.prototype.apply()

Function 实例的 apply() 方法使用给定的 this 值调用此函数,并以数组(或 类似数组的对象)的形式提供 arguments

¥The apply() method of Function instances calls this function with a given this value, and arguments provided as an array (or an array-like object).

Try it

语法

¥Syntax

js
apply(thisArg)
apply(thisArg, argsArray)

参数

¥Parameters

thisArg

为调用 func 提供的 this 值。如果函数不在 严格模式 中,则 nullundefined 将被替换为全局对象,并且原始值将被转换为对象。

argsArray Optional

类似数组的对象,指定应调用 func 的参数,如果不应向函数提供参数,则指定 nullundefined

返回值

¥Return value

使用指定的 this 值和参数调用函数的结果。

¥The result of calling the function with the specified this value and arguments.

描述

¥Description

注意:此函数几乎与 call() 相同,只是函数参数作为列表单独传递给 call(),而对于 apply(),它们组合在一个对象(通常是数组)中 - 例如,func.call(this, "eat", "bananas")func.apply(this, ["eat", "bananas"])

¥Note: This function is almost identical to call(), except that the function arguments are passed to call() individually as a list, while for apply() they are combined in one object, typically an array — for example, func.call(this, "eat", "bananas") vs. func.apply(this, ["eat", "bananas"]).

通常,当调用函数时,函数内部的 this 的值就是该函数被访问的对象。使用 apply(),你可以在调用现有函数时将任意值指定为 this,而无需首先将该函数作为属性附加到对象。这允许你将一个对象的方法用作通用实用程序函数。

¥Normally, when calling a function, the value of this inside the function is the object that the function was accessed on. With apply(), you can assign an arbitrary value as this when calling an existing function, without first attaching the function to the object as a property. This allows you to use methods of one object as generic utility functions.

你还可以使用任何类型的类似数组的对象作为第二个参数。实际上,这意味着它需要具有 length 属性和 (0..length - 1) 范围内的整数 ("index") 属性。例如,你可以使用 NodeList{ 'length': 2, '0': 'eat', '1': 'bananas' } 等自定义对象。你也可以使用 arguments,例如:

¥You can also use any kind of object which is array-like as the second parameter. In practice, this means that it needs to have a length property, and integer ("index") properties in the range (0..length - 1). For example, you could use a NodeList, or a custom object like { 'length': 2, '0': 'eat', '1': 'bananas' }. You can also use arguments, for example:

js
function wrapper() {
  return anotherFn.apply(null, arguments);
}

使用 其余参数 和参数 扩展语法,可以将其重写为:

¥With the rest parameters and parameter spread syntax, this can be rewritten as:

js
function wrapper(...args) {
  return anotherFn(...args);
}

一般来说,使用参数扩展语法,fn.apply(null, args) 相当于 fn(...args),但在使用 apply() 的情况下,args 预计是一个类数组对象,在使用扩展语法的情况下,args 预计是一个 iterable 对象。

¥In general, fn.apply(null, args) is equivalent to fn(...args) with the parameter spread syntax, except args is expected to be an array-like object in the former case with apply(), and an iterable object in the latter case with spread syntax.

警告:不要使用 apply() 来链接构造函数(例如,实现继承)。这将构造函数作为普通函数调用,这意味着 new.targetundefined,并且类会抛出错误,因为没有 new 就无法调用它们。请改用 Reflect.construct()extends

¥Warning: Do not use apply() to chain constructors (for example, to implement inheritance). This invokes the constructor function as a plain function, which means new.target is undefined, and classes throw an error because they can't be called without new. Use Reflect.construct() or extends instead.

示例

¥Examples

使用 apply() 将一个数组附加到另一个数组

¥Using apply() to append an array to another

你可以使用 Array.prototype.push() 将元素追加到数组中。由于 push() 接受可变数量的参数,因此你还可以一次推送多个元素。但是,如果将数组传递给 push(),它实际上会将该数组作为单个元素添加,而不是单独添加元素,最终得到数组内的数组。另一方面,在这种情况下,Array.prototype.concat() 确实具有所需的行为,但它不会追加到现有数组 - 它创建并返回一个新数组。

¥You can use Array.prototype.push() to append an element to an array. Because push() accepts a variable number of arguments, you can also push multiple elements at once. But if you pass an array to push(), it will actually add that array as a single element, instead of adding the elements individually, ending up with an array inside an array. On the other hand, Array.prototype.concat() does have the desired behavior in this case, but it does not append to the existing array — it creates and returns a new array.

在这种情况下,你可以使用 apply 来隐式 "spread" 一个数组作为一系列参数。

¥In this case, you can use apply to implicitly "spread" an array as a series of arguments.

js
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

使用扩展语法可以达到相同的效果。

¥The same effect can be achieved with the spread syntax.

js
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push(...elements);
console.info(array); // ["a", "b", 0, 1, 2]

使用 apply() 和内置函数

¥Using apply() and built-in functions

巧妙地使用 apply() 允许你使用内置函数来执行某些任务,否则这些任务可能需要手动循环集合(或使用扩展语法)。

¥Clever usage of apply() allows you to use built-in functions for some tasks that would probably otherwise require manually looping over a collection (or using the spread syntax).

例如,我们可以使用 Math.max()Math.min() 来找出数组中的最大值和最小值。

¥For example, we can use Math.max() and Math.min() to find out the maximum and minimum value in an array.

js
// min/max number in an array
const numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
let max = Math.max.apply(null, numbers);
// This about equal to Math.max(numbers[0], …)
// or Math.max(5, 6, …)

let min = Math.min.apply(null, numbers);

// vs. simple loop based algorithm
max = -Infinity;
min = +Infinity;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] > max) {
    max = numbers[i];
  }
  if (numbers[i] < min) {
    min = numbers[i];
  }
}

但要注意:通过将 apply()(或展开语法)与任意长的参数列表一起使用,你将面临超出 JavaScript 引擎的参数长度限制的风险。

¥But beware: by using apply() (or the spread syntax) with an arbitrarily long arguments list, you run the risk of exceeding the JavaScript engine's argument length limit.

调用带有太多参数(即超过数万个参数)的函数的后果是未指定的,并且因引擎而异。(JavaScriptCore 引擎有一个硬编码的 参数限制为 65536。)大多数引擎都会抛出异常;但没有规范规范来阻止其他行为,例如任意限制实际传递给应用函数的参数数量。为了说明后一种情况:如果这样的引擎限制为四个参数(实际限制当然要高得多),则就好像在上面的示例中参数 5, 6, 2, 3 已传递到 apply,而不是完整数组。

¥The consequences of calling a function with too many arguments (that is, more than tens of thousands of arguments) is unspecified and varies across engines. (The JavaScriptCore engine has a hard-coded argument limit of 65536.) Most engines throw an exception; but there's no normative specification preventing other behaviors, such as arbitrarily limiting the number of arguments actually passed to the applied function. To illustrate this latter case: if such an engine had a limit of four arguments (actual limits are of course significantly higher), it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.

如果你的值数组可能增长到数万个,请使用混合策略:一次将你的函数应用于数组的块:

¥If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:

js
function minOfArray(arr) {
  let min = Infinity;
  const QUANTUM = 32768;

  for (let i = 0; i < arr.length; i += QUANTUM) {
    const submin = Math.min.apply(
      null,
      arr.slice(i, Math.min(i + QUANTUM, arr.length)),
    );
    min = Math.min(submin, min);
  }

  return min;
}

const min = minOfArray([5, 6, 2, 3, 7]);

规范

Specification
ECMAScript Language Specification
# sec-function.prototype.apply

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看