Function.prototype.apply メソッド

Did you know that you can read content offline by using one of these tools? If you would like to read offline MDN content in another format, let us know by commenting on Bug 665750.

Dash App

この文書は翻訳中です。他国語のままの部分などがあるのはその為です。
是非お気軽に MDN に登録して翻訳に参加し、私たちの手助けをして下さい!

概要

関数内での this キーワードの値を明示的に指定して関数を呼び出します。 呼び出し先の関数に引数として渡される値は、配列に格納して call メソッドの第 2 引数で指定します。

注記: このメソッドは call() メソッドに似ていますが、呼び出し先関数に渡す引数の指定方法が異なります。 call() メソッドは、第 2 引数以降の引数をそのまま呼び出し先関数に渡す引数とします。
Function のメソッド
実装されたバージョン JavaScript 1.3
ECMAScript エディション ECMA-262 3rd Edition

構文

fun.apply(thisArg[, argsArray])

引数

thisArg
呼び出し先関数 fun の中で this パラメータとして使用される値です。 実際にこの値が関数の中で this の値として使用されるとは限りません: もし、関数が non-strict mode のコードで、nullundefined が指定された場合は this の値は global object になります。 また、プリミティブ値はボクシングされます。
argsArray
関数 fun の引数として渡される値を格納した配列のようなオブジェクト、もしくは nullundefinednullundefined の場合は、fun には引数が渡されません。

JavaScript 1.8.5 における注記

JavaScript 1.8.5 (Firefox 4) から、このメソッドは ECMAScript 5 仕様に従うようになりました。 つまり、これまで第 2 引数には配列を渡す必要がありましたが、配列のようなオブジェクトでも良いようになりました。この変更についての詳細は bug 562448 を参照してください。

バグ 562448

説明

関数を呼び出すときに、 this を別のオブジェクトに割り当てることができます。this は呼び出しているオブジェクト、現在のオブジェクトを参照します。apply を使うことで、一度メソッドを書いたあと、他のオブジェクトへ継承させるためにメソッドを書きなおさなくてもよくなります。

apply は、引数にとることのできる型を除いて call ととてもく似ています。ひとつの配列を名前をつけたパラメータの代わりに使うことができます。 apply には、 fun.apply(this, ['eat', 'bananas']) のような配列のリテラルや、 fun.apply(this, new Array('eat', 'bananas')) のような配列オブジェクトを使うことができます。

You can also use arguments for the argsArray parameter. arguments is a local variable of a function. It can be used for all unspecified arguments of the called object. Thus, you do not have to know the arguments of the called object when you use the apply method. You can use arguments to pass all the arguments to the called object. The called object is then responsible for handling the arguments.

ECMAScript 5から、配列のようなオブジェクトも渡すことができるようになりました。 これは、length というプロパティと、0から length までの整数のプロパティを持つオブジェクトのことです。例を挙げると、 As an example you can now use a NodeList or a own custom object like {'length': 2, '0': 'eat', '1': 'bananas'}.

註: Most browsers, including Chrome 14 and Internet Explorer 9, still do not accept array like objects and will throw an exception.

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

applyを使うことで、Javaのようなコンストラクタチェーンを実現することができます。以下の例では、constructというメソッドをグローバルなFunctionに作ります。このメソッドを使うことで、引数リストの代わりに配列のようなオブジェクトをコンストラクタに渡すことができるようにします。

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

alert(myInstance.property1); // alerts "Hello world!"
alert(myInstance instanceof MyConstructor); // alerts "true"
alert(myInstance.constructor); // alerts "MyConstructor"
注記: This non-native Function.construct method will not work with some native constructors (like Date, for example). In these cases you have to use the Function.bind method (for example, imagine to have an array like the following, to be used with Date constructor: [2012, 11, 4]; in this case you have to write something like: new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() – anyhow this is not the best way to do things and probably should not be used in any production environment).

apply and built-in functions

Clever usage of apply allows you to use built-ins functions for some tasks that otherwise probably would have been written by looping over the array values. As an example here we are going to use Math.max/Math.min to find out the maximum/minimum value in an array.

/* 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];
}

But beware: in using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit 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:

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

関連情報

タグ (2)