JavaScript アドバンス

JavaScript apply() メソッド

1. メソッドの再利用

apply() メソッドを使用すると、異なるオブジェクト間でメソッドを共有し、再利用することができます。
このメソッドは、特定の this を指定して関数を呼び出すために使用されます。
apply() は以前解説した call() メソッドと非常によく似ていますが、引数(Arguments)を配列として渡す点が異なります。

apply() はアドバンスド(高度)なトピックです。
先に進む前に、this キーワードおよび call() メソッドについて理解していることを確認してください。

2. apply() の基本構文

apply() メソッドは、オブジェクトを引数として関数を呼び出すために使用されます。

  • 第1引数には、関数内での this となるオブジェクトを渡します。
  • 第2引数には、関数に渡す値を格納した 配列(Array) を渡します。

2.1 構文

functionName.apply(thisArg, [arg1, arg2, ...]);

3. apply() を使った this の設定

apply() を使用すると、this がどのオブジェクトを参照するかを自由に決定できます。
以下の例では、greet 関数が「挨拶 + this.name」を返します。
apply() を使うことで、thisperson3 オブジェクトに指定しています。

3.1 実装例

const person1 = { name: "ジョン" };
const person2 = { name: "ポール" };
const person3 = { name: "リンゴ" };

function greet(greeting) {
  return greeting + " " + this.name;
}

// this を person3 に指定し、引数を配列形式で渡す
greet.apply(person3, ["こんにちは"]);

4. call() と apply() の違い

apply()call() の唯一の違いは、引数の渡し方です。

  • call() メソッド:引数を 個別に(カンマ区切りで) 受け取ります。
  • apply() メソッド:引数を 配列として 受け取ります。

引数がすでに配列の中に格納されている場合は、apply() を使用するのが非常に効率的です。

4.1 比較例

// call の場合
greet.call(person, "こんにちは");

// apply の場合
greet.apply(person, ["こんにちは"]);

5. 他のオブジェクトからのメソッド借用

apply() を使用して、他のオブジェクトから メソッドを借用(Method Borrowing) することができます。

5.1 例1:person1 に対してメソッドを適用

person オブジェクトの fullName メソッドを、person1 に対して適用します。

// person オブジェクトを作成
const person = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}

// person1 オブジェクトを作成
const person1 = {
  firstName: "ジョン",
  lastName: "ドウ"
}

// person2 オブジェクトを作成
const person2 = {
  firstName: "メアリー",
  lastName: "ドウ"
}

// "ジョン ドウ" を返す
person.fullName.apply(person1);

この2つの例において、apply() メソッドの挙動は call() メソッドと全く同じです。

5.2 例2:person2 に対してメソッドを適用

同様に、person2 に対してメソッドを適用します。

// "メアリー ドウ" を返す
person.fullName.call(person2);

6. 引数を伴う apply() メソッド

apply() メソッドは、配列形式で引数を受け取ります。
すべての引数は、正しい順番で配列内に配置されている必要があります。

6.1 実装例

const person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}

const person1 = {
  firstName: "ジョン",
  lastName: "ドウ"
}

// 第二引数に配列 [city, country] を渡す
person.fullName.apply(person1, ["オスロ", "ノルウェー"]);

6.2 call() メソッドとの比較

const person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}

const person1 = {
  firstName: "ジョン",
  lastName: "ドウ"
}

// 個別の引数として渡す
person.fullName.call(person1, "オスロ", "ノルウェー");

7. apply() を使った配列操作のシミュレーション

apply() の一般的なユースケースとして、配列に対して Math 関数を適用することが挙げられます。
Math.max() メソッドは、引数のリストの中から最大の数値を返します。

7.1 通常の Math.max()

Math.max(4, 8, 5, 1);  // 8 を返す

JavaScript の配列(Array)自体には max() メソッドはありませんが、apply() を使うことでこれを シミュレート できます。

7.2 配列に Math.max() を適用する

const numbers = [4, 8, 5, 1];

// Math.max は this を必要としないため、第一引数に null を渡す
Math.max.apply(null, numbers);

上記の例では、Math.max()this 値を必要としないため、第1引数に null を指定しています。
以下の例もすべて同じ結果を返します。

Math.max.apply(" ", numbers);
Math.max.apply(0, numbers);

8. JavaScript の Strict モード

JavaScript の Strict モード(厳格モード) では、apply() メソッドの第1引数がオブジェクトでない場合、それが呼び出された関数のオーナー(オブジェクト)になります。
非厳格モード(Non-strict mode)では、グローバルオブジェクトに置き換えられます。

9. apply() は新しい関数を作成しない

call() メソッドと同様に、apply() メソッドも 関数を即座に実行 します。
新しい関数を返して後で呼び出せるようにするものではありません。

9.1 実装例

function sum(a, b) {
  return a + b;
}

// その場ですぐに実行される
sum.apply(null, [4, 5]);

もし、同じ this を保持したまま、後で呼び出すための関数が必要な場合は、apply() ではなく bind() メソッドを使用してください。