apply() メソッドは与えられた this 参照値と、配列(もしくは配列風のオブジェクト)の形で与えられた引数を用いて関数を呼び出します。
call() メソッドとほぼ同じですが、根本的な違いは apply() メソッドが引数の配列を一つだけ受け取るのに対して、 call() メソッドは連続した引数のリストを受け取るという点です。構文
fun.apply(thisArg[, argsArray])
引数
thisArg- この値は
fun関数を呼び出す際に渡すthisの値です。このメソッドで指定した this が必ず呼び出したメソッドで参照される訳ではない事に注意して下さい。もし呼び出したメソッドが non-strict mode 内の関数であれば、ここで渡した値がnullもしくはundefinedであった場合はグローバル・オブジェクトに置き換えられ、プリミティブ型の変数はボックス化されます。 argsArray- 一つの配列風のオブジェクトであり、
fun関数が呼ぶことに成る引数を列挙したものです。関数に引数が渡されない場合はnullあるいはundefined値となります。ECMAScript 5 以降ではこれらの値は配列ではなく配列風のオブジェクトを用いる事になりました。ブラウザ間の互換性に関しては下に示した表を参照してください。
戻り値
指定した this 値と引数で関数を呼び出した結果。
解説
存在する関数を呼び出す時は通常と異なる this オブジェクトを渡すことができます。 this はカレントオブジェクト、呼び出したオブジェクトを参照します。apply を用いることで、新たなオブジェクトのためにそのメソッドを書き直すこと無く継承させることができます。
apply は対応する引数の型を除いて call() に非常に似ています。仮引数の組み合わせの代わりに引数の配列を用いる事ができます。apply はリテラル表記の配列を用いることもでき、例えば fun.apply(this, ['eat', 'bananas']) のように利用でき、同様に配列オブジェクトを fun.apply(this, new Array('eat', 'bananas')) のように利用できます。
argsArray の値を arguments で利用する事もできます。arguments は関数内で利用できるローカル変数です。この値は不特定の呼び出された全てのオブジェクトを利用するために用いられます。つまり、 apply メソッドを使うにあたって呼び出されたオブジェクトの引数について知る必要が無いのです。arguments を利用することで呼び出されたオブジェクトに引数を全て渡す事もできます。この呼びだされたオブジェクトはその引数を操作できる状態になります。
ECMAScript 第5版ではまた配列風である、具体的には length プロパティを持ち、 0 以上 length 未満の範囲の整数を名称としたプロパティを持った、あらゆる種類のオブジェクトの利用を認めています。そのため例えば NodeList や {'length': 2, '0': 'eat', '1': 'bananas'} のような独自のオブジェクトを利用する事もできます。
Chrome 14 や Internet Explorer 9 を含むほとんどのブラウザはまだ配列風オブジェクトを apply で受け取ることができずエラーが出力されます。
例
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() メソッドは比較的新しいです。クロージャーを使用する代替えメソッドとして、以下の例を検討してください:
Function.prototype.construct = function(aArgs) {
var fConstructor = this, fNewConstr = function() {
fConstructor.apply(this, aArgs);
};
fNewConstr.prototype = fConstructor.prototype;
return new fNewConstr();
};
使用例:
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); // logs 'Hello world!'
console.log(myInstance instanceof MyConstructor); // logs 'true'
console.log(myInstance.constructor); // logs 'MyConstructor'
Function.construct メソッドはいくつかのネイティブ実装されたコンストラクタ(例えば Date のような物)と併用できません。このようなケースにおいては Function.bind メソッドを利用する必要が有ります。(例えば [2012, 11, 4] のような配列を利用する事を想定して下さい。この場合では次のように記述する必要が有ります。new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() - いずれにせよこれは最適な選択肢とは言えず、実用上はいかなる状況でも用いるべきではないでしょう。)apply をビルトイン関数と共に利用する
apply をより効果的に利用するといくつかの、ビルトイン関数によって配列とループを駆使すること無く容易に行う処理が可能になります。以下に示す例では配列の中の最大値・最小値を求めるために Math.max/Math.min 関数を利用しています。
/* min/max number in an array */
var numbers = [5, 6, 2, 3, 7];
/* using Math.min/Math.max apply */
var max = Math.max.apply(null, numbers); /* This about equal to Math.max(numbers[0], ...)
or Math.max(5, 6, ..) */
var min = Math.min.apply(null, numbers);
/* vs. simple loop based algorithm */
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であるとハードコーディングされています)異なります。例外を投げるエンジンも存在します。ただ酷いものでは利用された関数に、実際は渡せているにも関わらず参照できる引数の数を制限している物もあります(後者のエンジンに関して詳しく解説しますと、そのエンジンが arguments の上限を 4 つとしていた場合 [実際の上限値は当然もっと上です]、 上の例のコードでは完全な配列でなく、さも 5, 6, 2, 3 だけが apply に渡されてきたかのように動作します)。もし実装しているコードで利用する配列の変数の数が数万を超えそうなときは、以下に示すように一度に 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]);
"monkey-patching" で apply を利用する
apply は Firefox のビルドイン関数や JS ライブラリに monkey-patch を行う最良の方法です。someobject.foo 関数を提供するために、関数をややハッキーな方法で次のように修正できます
var originalfoo = someobject.foo;
someobject.foo = function() {
// Do stuff before calling function
console.log(arguments);
// Call the function as it would have been called normally:
originalfoo.apply(this, arguments);
// Run stuff after, here.
}
このメソッドは、インスペクタなどでで利用できる .on([event]...) イベントのような API がない場所でイベントやインターフェースをデバッグするときに特に役立ちます。
仕様
| 仕様 | ステータス | コメント |
|---|---|---|
| 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 2017 Draft (ECMA-262) Function.prototype.apply の定義 |
ドラフト |
ブラウザ互換性
| 機能 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|
| 基本サポート | (有) | (有) | (有) | (有) | (有) |
|
ES 5.1 generic array-like object as arguments
|
? | 4.0 (2.0) | ? | ? | ? |
| 機能 | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
| 基本サポート | (有) | (有) | (有) | (有) | (有) | (有) |
|
ES 5.1 generic array-like object as arguments
|
? | ? | 4.0 (2.0) | ? | ? | ? |