Function.prototype.apply()

概要

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

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

構文

fun.apply(thisArg[, argsArray])

引数

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

解説

存在する関数を呼び出す時は通常と異なる 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 fConstructor = this, fNewConstr = function () { fConstructor.apply(this, aArgs); };
    fNewConstr.prototype = fConstructor.prototype;
    return new fNewConstr();
};

Example usage:

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

alert(myInstance.property1); // alerts "Hello world!"
alert(myInstance instanceof MyConstructor); // alerts "true"
alert(myInstance.constructor); // alerts "MyConstructor"
Note: この非ネイティブな 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]);

仕様

仕様書 状態 備考
ECMAScript 3rd Edition. Implemented in JavaScript 1.3. Standard Initial definition.
ECMAScript Language Specification 5.1th Edition (ECMA-262) Standard  
ECMAScript Language Specification 6th Edition (ECMA-262) ドラフト  

ブラウザ互換性

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (有) (有) (有) (有) (有)
ES 5.1 generic array-like object as arguments
? 4.0 (2.0) ? ? ?
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support (有) (有) (有) (有) (有) (有)
ES 5.1 generic array-like object as arguments
? ? 4.0 (2.0) ? ? ?

参考

Document Tags and Contributors

タグ:
Contributors to this page: nobuoka, ethertank, yuxxxx, takashi
最終更新者: takashi,