JavaScript の bind() メソッド
1. メソッド借用 (Method Borrowing)
call() や apply() と同様に、bind() メソッドを使用すると、他のオブジェクトからメソッドを借用(Borrow)することができます。
ただし、call() や apply() とは決定的な違いがあります。bind() メソッドは 関数を即座に実行しません。
その代わりに、後で呼び出すことができる「新しい関数」を返します。
この新しい関数は、あなたが指定した this の値を永続的に保持(記憶)します。
bind() はアドバンスド(高度)なトピックです。続行する前に、this、call()、および apply() を理解していることを確認してください。
2. bind() の基本構文
bind() メソッドは新しい関数を作成します。
- 第1引数で、新しい関数のための
thisの値を設定します。 - 第2引数以降は、新しい関数における 固定された引数 となります。
2.1 構文
const newFunction = functionName.bind(thisArg, arg1, arg2, ...);3. this を固定するための bind() 使用法
bind() の最も一般的な用途は、関数が常に同じ this 値を使用するように保証することです。
3.1 実装例
const person1 = { name: "ジョン" };
const person2 = { name: "ポール" };
const person3 = { name: "リンゴ" };
function greet() {
return "こんにちは " + this.name;
}
// this を person1 に固定した新しい関数を作成
const greetJohn = greet.bind(person1);
greetJohn(); // "こんにちは ジョン" を返すgreetJohn は、常に person1 を this として使用する新しい関数です。
3.2 オブジェクト間でのメソッド借用
以下の例では、person と member という2つのオブジェクトを作成しています。member オブジェクトが person オブジェクトから fullName メソッドを借用します。
// person オブジェクトを作成
const person = {
firstName: "ジョン",
lastName: "ドウ",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
// member オブジェクトを作成
const member = {
firstName: "ヘゲ",
lastName: "ニルセン",
}
// fullName メソッドを member オブジェクトにバインド(束縛)
let fullName = person.fullName.bind(member);
// 後で fullName() を呼び出す
fullName(); // "ヘゲ ニルセン"4. bind() vs call() と apply()
これらのメソッドの違いを理解することは非常に重要です。
call(): 関数を 即座に 呼び出すapply(): 関数を 即座に 呼び出すbind(): 新しい関数を返す
4.1 比較例
// 関数を即座に呼び出す
greet.call(person);
// 関数を即座に呼び出す
greet.apply(person);
// 新しい関数を作成する(実行はされない)
const greetLater = greet.bind(person);
// 後で新しい関数を呼び出す
greetLater();5. 後で呼び出される関数のための bind()
bind() を使用しないと、this の値が失われてしまう(意図しないものに変わる)ことがあります。
5.1 this が失われる例
const person = {
name: "ジョン",
sayHello: function() {
return "こんにちは " + this.name;
}
};
// メソッドを変数に代入(ここで this のコンテキストが切り離される)
const hello = person.sayHello;
hello(); // this は person ではないため、期待通りに動作しない5.2 bind() による解決
// person に bind することで、コンテキストを固定する
const hello = person.sayHello.bind(person);
hello(); // 正常に動作する6. this を維持するための bind() 利用
bind() メソッドは、this の消失を防ぐ ために使用できます。
以下の例では、person オブジェクトに display メソッドがあります。このメソッド内では、this は person オブジェクトを参照しています。
const person = {
firstName: "ジョン",
lastName: "ドウ",
display: function () {
let x = document.getElementById("demo");
x.innerHTML = this.firstName + " " + this.lastName;
}
}
person.display();しかし、関数を コールバック(Callback) として使用すると、this は失われます。
例えば、setTimeout() の中で person.display を使用してみましょう。
6.1 this が消失するケース(setTimeout)
// これは名前の代わりに undefined を表示します
const person = {
firstName: "ジョン",
lastName: "ドウ",
display: function () {
let x = document.getElementById("demo");
x.innerHTML = this.firstName + " " + this.lastName;
}
}
// 3秒後に実行される際、this が person を指さなくなっている
setTimeout(person.display, 3000);6.2 bind() による解決策
bind() メソッドはこの問題を解決します。
// 正しく表示されます
const person = {
firstName: "ジョン",
lastName: "ドウ",
display: function () {
let x = document.getElementById("demo");
x.innerHTML = this.firstName + " " + this.lastName;
}
}
// person.display を person オブジェクトに bind する
let display = person.display.bind(person);
setTimeout(display, 3000);7. 引数を伴う bind()
bind() に渡された引数は、新しい関数における 固定された値 になります。
これは 部分適用 (Partial Application) と呼ばれることもあります。
7.1 実装例
function multiply(a, b) {
return a * b;
}
// 第1引数 a を 2 に固定した新しい関数を作成
const double = multiply.bind(null, 2);
double(5); // 2 * 5 = 10 を返すこの double 関数は、常に最初の引数として 2 を使用するようになります。
8. bind() は元の関数を変更しない
bind() を実行しても、元の関数自体が書き換えられることはありません。bind() を呼び出すたびに、常に 新しい関数 が生成されます。
8.1 実装例
// それぞれ異なる this を持った新しい関数が生成される
const greetJohn = greet.bind({ name: "ジョン" });
const greetAnna = greet.bind({ name: "アンナ" });