apply() メソッドは与えられた this 参照値と、配列 (もしくは配列風のオブジェクト) の形で与えられた引数を用いて関数を呼び出します。

注: 関数の構文は call() メソッドとほぼ同じですが、根本的な違いは apply() メソッドが引数の配列を 1 つだけ受け取るのに対して、 call() メソッドは連続した引数のリストを受け取るという点です。

構文

func.apply(thisArg, [argsArray])

引数

thisArg
この値は func 関数を呼び出す際に渡す this の値です。このメソッドで指定した this が必ず呼び出したメソッドで参照されるわけではないことに注意してください。もし呼び出したメソッドが non-strict mode 内の関数であれば、ここで渡した値が null もしくは undefined であった場合はグローバル・オブジェクトに置き換えられ、プリミティブ型の変数はボックス化されます。
argsArray
1 つの配列風のオブジェクトであり、 func 関数が呼ぶことになる引数を列挙したものです。関数に引数が渡されない場合は null または undefined となります。ECMAScript 5 以降ではこれらの値は配列ではなく配列風のオブジェクトを用いる事になりました。後述のブラウザー実装状況を参照してください。

戻り値

指定した this と引数で関数を呼び出した結果が返ります。

解説

存在する関数を呼び出す時は通常と異なる this オブジェクトを渡すことができます。this はカレントオブジェクト、呼び出したオブジェクトを参照します。apply を用いることで、新たなオブジェクトのためにそのメソッドを書き直すことなく継承させることができます。

apply は、対応する引数の型を除けば call() によく似ています。引数のリストの代わりに引数の配列を用いることができます。apply は配列リテラルを引数に用いることもできます。例えば func.apply(this, ['eat', 'bananas']) のように利用でき、同様に配列オブジェクトを func.apply(this, new Array('eat', 'bananas')) のように利用できます。

argsArrayarguments を利用することもできます。arguments は関数内のローカル変数です。これは、呼び出されたオブジェクトの不特定の引数すべてに対して用いることができます。つまり、 apply メソッドを使うにあたって呼び出されたオブジェクトの引数について知る必要がないのです。arguments を利用することで、引数のすべてを呼び出されたオブジェクトに渡すことができます。引数の扱いは、呼び出されたオブジェクトが受け持ちます。

ECMAScript 第5版以降では、配列風のオブジェクトも使えます。具体的には、length プロパティとその範囲 (0 から length-1 まで) の整数の名称のプロパティを持った、あらゆる種類のオブジェクトの利用を認めています。例えば、NodeList{ 'length': 2, '0': 'eat', '1': 'bananas' } のような独自のオブジェクトを利用できます。

Chrome 14 や Internet Explorer 9 などのブラウザでは、配列風オブジェクトを扱えずに例外がスローされます。

apply で配列を別の配列に追加する

push で 1 つの要素を配列に追加できます。そして、push は可変長引数に対応しているので、複数の要素を一度に追加することもできます。しかし push に配列を渡すと、配列の要素ごとにではなく配列全体を 1 つの要素として追加してしまいます。配列の中に配列が入るだけなのです。それを望まない場合はどうすればいいのでしょう?concat ならば望みの結果を得られます。しかし、既存の配列に追加するのではなく、新しい配列を生成して返します。既存の配列に追加したいのに... では、どうすれば?ループ文を書きますか?おことわりですよね?

apply が救ってくれます!

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

apply をビルトイン関数と共に利用する

apply を賢く使うと、本来なら配列のためにループ文を書かなくてはならないような処理に対して、ビルトイン関数をそのまま使えるようになります。下記の例では、配列の最大値・最小値を求めるために Math.max/Math.min を使っています。

// 最小値・最大値を求めたい配列
var numbers = [5, 6, 2, 3, 7];

// Math.min/Math.max と apply を使う
var max = Math.max.apply(null, numbers); 
// これは右と同じ Math.max(numbers[0], numbers[1], ...)
// または Math.max(5, 6, ...)

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

// 対して、ループ文を使うとこうなる
max = -Infinity, min = +Infinity;

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

しかし注意してください。この方法で apply を使う場合、JavaScript エンジンの引数の長さ上限を超えてしまう危険があります。多すぎる (おおよそ数万個以上だと思って下さい) 引数を与えた結果は、その上限が特に決まっていない (本当に任意の巨大なデータのかたまりに対してさえ) ためエンジンによって (JavaScriptCore ライブラリでは引数の上限は65536であるとハードコーディングされています) 異なります。例外を投げるエンジンも存在します。さらに酷い場合では、関数へ実際に渡す引数の数を勝手に制限するものもあります。後者について詳しく解説しますと、そのエンジンの引数の上限が 4 つの場合 (実際の上限値は当然もっと上です)、上の例では、完全な配列でなく 5, 6, 2, 3apply へ渡されたかのような動作をします。

もし実装しているコードで利用する配列の変数の数が数万を超えそうなときは、以下に示すように一度に apply に渡す配列を分割して利用する方法を併用すべきでしょう。

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

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

  return min;
}

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

 

apply を利用したコンストラクタチェーン

apply を利用して、Java のように constructors の連結を行なうことができます。以下に示す例ではグローバルな construct という名称の Function オブジェクトを作成し、引数のリストの代わりに配列風オブジェクトをコンストラクタと共に利用できるようになります。

Function.prototype.construct = function(aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

注: 上記で使用している Object.create() メソッドは比較的新しいです。代わりの方法として、以下の例を検討してください。

Object.__proto__ を利用:

Function.prototype.construct = function (aArgs) {
  var oNew = {};
  oNew.__proto__ = this.prototype;
  this.apply(oNew, aArgs);
  return oNew;
};

クロージャを利用:

Function.prototype.construct = function(aArgs) {
  var fConstructor = this, fNewConstr = function() { 
    fConstructor.apply(this, aArgs); 
  };
  fNewConstr.prototype = fConstructor.prototype;
  return new fNewConstr();
};

Function コンストラクタを利用:

Function.prototype.construct = function (aArgs) {
  var fNewConstr = new Function("");
  fNewConstr.prototype = this.prototype;
  var oNew = new fNewConstr();
  this.apply(oNew, aArgs);
  return oNew;
};

使用例:

function MyConstructor() {
  for (var nProp = 0; nProp < arguments.length; nProp++) {
    this['property' + nProp] = arguments[nProp];
  }
}

var myArray = [4, 'Hello world!', false];
var myInstance = MyConstructor.construct(myArray);

console.log(myInstance.property1);                // Hello world!
console.log(myInstance instanceof MyConstructor); // true
console.log(myInstance.constructor);              // MyConstructor

注: この非ネイティブな Function.construct メソッドはいくつかのネイティブ実装されたコンストラクタ (例えば Date のような物) と併用できません。このようなケースにおいては Function.bind メソッドを利用する必要があります。 (例えば [2012, 11, 4] のような配列を利用する事を想定してください。この場合では次のように記述する必要が有ります。new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() - いずれにせよこれは最適な選択肢とは言えず、実用上はいかなる状況でも用いるべきではないでしょう)

仕様

仕様書 策定状況 コメント
ECMAScript 3rd Edition (ECMA-262) 標準 初期定義。JavaScript 1.3 で実装
ECMAScript 5.1 (ECMA-262)
Function.prototype.apply の定義
標準  
ECMAScript 2015 (6th Edition, ECMA-262)
Function.prototype.apply の定義
標準  
ECMAScript Latest Draft (ECMA-262)
Function.prototype.apply の定義
ドラフト  

ブラウザー実装状況

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung InternetNode.js
基本対応Chrome 完全対応 ありEdge 完全対応 ありFirefox 完全対応 1IE 完全対応 ありOpera 完全対応 ありSafari 完全対応 ありWebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 ありFirefox Android 完全対応 4Opera Android 完全対応 ありSafari iOS 完全対応 ありSamsung Internet Android 完全対応 ありnodejs 完全対応 あり
ES 5.1: generic array-like object as argumentsChrome 完全対応 ありEdge ? Firefox 完全対応 4IE ? Opera ? Safari ? WebView Android ? Chrome Android 完全対応 ありEdge Mobile ? Firefox Android 完全対応 4Opera Android ? Safari iOS ? Samsung Internet Android 完全対応 ありnodejs ?

凡例

完全対応  
完全対応
実装状況不明  
実装状況不明

関連情報

ドキュメントのタグと貢献者

このページの貢献者: sutara79, dlwe, YuichiNukiyama, .Hiroya, takashi, yuxxxx, ethertank, nobuoka
最終更新者: sutara79,