apply
メソッドと似ているメソッドとしてcall
メソッドがあります。
主な違いはapply
メソッドは第 2 引数以降は一つの引数を受け取るのに対し、call
メソッドは第 2 引数以降複数の引数を受けとれるということです。
ここではapply
について、私が理解した範囲内で書いていきます。
まず apply メソッドの構文です。
func.apply(thisArg, [argsArray]);
MDN サイトに記載されているものをそのまま持ってきました。私の理解を交えながら説明します。
apply
メソッドは、ある関数func
から呼び出すことができます。
第 1 引数のthisArg
はfunc
関数内のthis
の新たな参照先です。
func
内でthis
が呼び出されていない場合、thisArg
にはnull
またはundefined
を代入することも可能です。
第 2 引数のargsArray
は配列風のオブジェクト?で、func
関数が呼ぶことになる引数を列挙したものになります。
例えばfn1(a, b, c)
という関数において、関数fn1
内のthis
を関数fn2
に向けたい場合、apply
を使うとfn1.apply(fn2, [a, b, c])
のようになります。
apply
メソッドの使い方を具体例で見てみます。
function User(name) {
this.name = name;
}
User.prototype.getName = function () {
return this.name;
};
const user1 = new User("太郎");
const user2 = new User("花子");
console.log(user1.getName()); // 太郎
console.log(user2.getName()); // 花子
console.log(user1.getName.apply(user2)); // 花子
apply
は、apply
メソッドを呼び出した関数内のthis
のあて先を、apply
メソッドの第 1 引数で渡したオブジェクトに向けなおす機能があります。
上記コードでは、User
というコンストラクタ関数を作成しました。
user1 では name 属性として「太郎」、user2 では name 属性として「花子」を格納しました。
さらに name を取得する getName メソッドを定義しました。
user1.getName()
とuser2.getName()
では、getName メソッドを呼び出しているオブジェクトが所持している name を返しています。
しかしuser1.getName.apply(user2)
では、getName を呼び出している user1 の name ではなく、apply
の第 1 引数である user2 の name を返しています。
これは、getName メソッド内のthis
の参照先がapply
メソッドによって user1 から user2 に変更されたからだとわかります。
const numbers = [4, 9, 1, 6, 8, 3];
const max = Math.max.apply(null, numbers);
console.log(max); // 9
もしapply
の役割として「this
の参照先を変える」しか知らないと、上記のMath.max.apply(null, numbers)
の第 1 引数としてnull
を見た瞬間、「this
の参照先をなくしているからapply
の意味ないじゃない?」と思うはずです。
これは先ほど述べたように、Math.max
関数内ではthis
を使用していないため、null
を渡しても問題ないからです。
ではここでapply
を使った意味は何でしょうか?
もし単純に numbers 配列内の最大要素を求めようとして、Math.max(numbers)
とすると、NaN
が返されます。
これは Math.max メソッドはMath.max(1,2,3,4,5)
みたいに引数を代入する必要があり、直接配列を渡すことができないからです。
そこでapply
を使ってMath.max.apply(null, numbers)
のようにすると、イメージ的にはapply
メソッドがnumbers
配列内の要素を一つずつ取り出してMath.max
の引数に渡してあげていると考えることができます。
つまりMath.max.apply(null, [4, 9, 1, 6, 8, 3])
がMath.max(4, 9, 1, 6, 8, 3)
になると考えることができます。 (Math.max(...numbers)
でできるやん!ってことはさておき...)
以上をまとめると、apply
の使い方として
- 関数内の
this
の参照先を変えることができる - ある配列内の要素を for 文みたいにいい感じに 1 個ずつ取り出して別の関数の引数として渡すことができる