staticメソッドにオブジェクトのメソッドを渡す際の注意点
JavaScriptやTypeScriptなどの言語において、staticなメソッドにオブジェクトのメソッドを直接渡すと、オブジェクト内のメンバー変数が参照できないという問題があります。
この記事では、具体的なコード例とその原因、解決策について解説します。
問題の背景
次のような状況を考えてみましょう。
- クラス
Aにはstaticなメソッドfuncがあります。 - クラス
Objには、メンバー変数iとメソッドmethod1があります。 - 外部から
Objのインスタンスobjを生成し、A.funcに引数としてobj.method1を渡します。 -
A.func内でobj.method1が呼び出されますが、その中でiにアクセスしようとすると「NotFound」のエラーが発生します。
この問題をコードで再現してみましょう。
問題のコード例
class A {
static func(callback: () => void) {
callback(); // 引数で渡されたメソッドを呼び出す
}
}
class Obj {
private i: number = 42;
method1() {
console.log(this.i); // iを参照しようとする
}
}
// 外部でObjインスタンスを生成
const obj = new Obj();
// staticメソッドに、obj.method1を渡す
A.func(obj.method1); // 実行時エラー: Cannot read property 'i' of undefined
エラーの原因
上記のコードを実行すると、obj.method1内でthis.iにアクセスしようとした際に「Cannot read property 'i' of undefined」というエラーが発生します。
このエラーの原因は、obj.method1がA.funcに渡された時点で「thisがバインドされていない」ことです。
通常、JavaScriptではメソッドを単体で渡した場合、そのメソッド内でのthisの参照が失われ、undefinedとなります。
結果として、メンバー変数iにアクセスできなくなってしまいます。
解決策
この問題を解決するには、2つの方法があります。
1. bindを使ってthisをバインドする
obj.method1をA.funcに渡す前に、bindを使ってthisをobjに固定します。
A.func(obj.method1.bind(obj)); // 正常に動作する
2. オブジェクトそのものを渡し、内部でメソッドを呼び出す
A.funcにobjごと渡して、funcの中でメソッドを呼び出すようにする方法です。
class A {
static func(instance: Obj) {
instance.method1(); // obj.method1を呼び出す
}
}
A.func(obj); // 正常に動作する
この方法では、func内でオブジェクトobjそのものにアクセスできるため、thisの問題が発生しません。
まとめ
staticメソッドにオブジェクトのメソッドを直接渡すと、thisの参照が失われるため、メンバー変数にアクセスできなくなります。この問題は、bindでthisをバインドするか、オブジェクト全体を渡してメソッドを呼び出すことで解決できます。
参考コード
class A {
static func(instance: Obj) {
instance.method1();
}
}
class Obj {
private i: number = 42;
method1() {
console.log(this.i);
}
}
const obj = new Obj();
A.func(obj); // 正常に動作し、42が出力される
このようにstaticメソッドとthisのバインドに関する問題に気をつけながら、安全にメソッドを使用しましょう。