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 個ずつ取り出して別の関数の引数として渡すことができる