Function.prototype.apply()

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

apply() 方法用於呼叫一個函式,該函式有一個給定的 this 值,以及以陣列(或 類陣列物件)形式提供的引數。

試一試

const numbers = [5, 6, 2, 3, 7];

const max = Math.max.apply(null, numbers);

console.log(max);
// Expected output: 7

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

console.log(min);
// Expected output: 2

語法

js
apply(thisArg)
apply(thisArg, argsArray)

引數

thisArg

為呼叫 func 提供的 this 值。如果函式不在 嚴格模式下,nullundefined 將被替換為全域性物件,原始值將被轉換為物件。

argsArray 可選

一個類陣列物件,指定了呼叫 func 時應使用的引數,如果不想為函式提供任何引數,則可以為 nullundefined

返回值

指定 this 值和引數呼叫函式的結果。

描述

注意: 這個函式幾乎與 call() 相同,只是 call() 將函式引數作為單獨的列表傳入,而 apply() 則將它們組合在一個物件中(通常是陣列)——例如,func.call(this, "eat", "bananas") 對比 func.apply(this, ["eat", "bananas"])

通常,在呼叫函式時,函式內部的 this 值是函式被訪問的物件。透過 apply(),您可以在呼叫現有函式時將任意值分配給 this,而無需先將函式作為屬性附加到物件上。這允許您將一個物件的方法用作通用實用函式。

您還可以使用任何類陣列物件作為第二個引數。實際上,這意味著它需要有一個 length 屬性,以及一個整數(“索引”)屬性,其範圍為 (0..length - 1)。例如,您可以使用 NodeList,或者一個自定義物件,如 { 'length': 2, '0': 'eat', '1': 'bananas' }。您也可以使用 arguments,例如

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

使用 剩餘引數和引數 展開語法,可以改寫為

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

一般來說,fn.apply(null, args) 等同於帶有引數展開語法的 fn(...args),只是 apply() 期望 args 是一個類陣列物件,而展開語法期望的是一個 可迭代 物件。

警告: 請勿使用 apply() 來連結建構函式(例如,來實現繼承)。這會將建構函式作為普通函式呼叫,這意味著 new.targetundefined,並且類會因為無法在沒有 new 的情況下呼叫而丟擲錯誤。請改用 Reflect.construct()extends

示例

使用 apply() 將一個數組追加到另一個數組

您可以使用 Array.prototype.push() 將一個元素追加到陣列中。因為 push() 接受可變數量的引數,所以您也可以一次性追加多個元素。但是,如果您將一個數組傳遞給 push(),它實際上會將該陣列作為一個單獨的元素新增,而不是單獨新增元素,最終結果是陣列中包含一個數組。另一方面,Array.prototype.concat() 在這種情況下可以實現所需行為,但它不會追加到現有陣列——它會建立並返回一個新陣列。

在這種情況下,您可以使用 apply 來隱式地將一個數組“展開”為一系列引數。

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

使用展開語法可以達到相同的效果。

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

使用 apply() 和內建函式

巧妙使用 apply() 可以讓您使用內建函式來完成一些原本可能需要手動迴圈遍歷集合(或使用展開語法)的任務。

例如,我們可以使用 Math.max()Math.min() 來找出陣列中的最大值和最小值。

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. loop based algorithm
max = -Infinity;
min = Infinity;

for (const n of numbers) {
  if (n > max) {
    max = n;
  }
  if (n < min) {
    min = n;
  }
}

但請注意:使用 apply()(或展開語法)並傳入任意長度的引數列表,您可能會面臨超出 JavaScript 引擎引數長度限制的風險。

用過多的引數(即,超過數萬個引數)呼叫函式的後果是未定義的,並且因引擎而異。(JavaScriptCore 引擎有一個硬編碼的 引數限制,為 65536)。大多數引擎會丟擲異常;但沒有規範性說明可以阻止其他行為,例如任意限制實際傳遞給被應用函式的引數數量。為了說明後一種情況:如果某個引擎的限制是四個引數(實際限制當然遠高於此),那麼在上面的示例中,就好像只將引數 5, 6, 2, 3 傳遞給了 apply,而不是整個陣列。

如果您的值陣列可能會增長到數萬個,請使用混合策略:一次將函式應用於陣列的各個塊

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]);

規範

規範
ECMAScript® 2026 語言規範
# sec-function.prototype.apply

瀏覽器相容性

另見