[解決済み] TypeScript "this" scoping issue when called in jquery callback.
2022-09-25 15:45:50
質問
TypeScriptで"this"のスコープを処理するための最適なアプローチがわかりません。
私がTypeScriptに変換しているコードによくあるパターンの例です。
class DemonstrateScopingProblems {
private status = "blah";
public run() {
alert(this.status);
}
}
var thisTest = new DemonstrateScopingProblems();
// works as expected, displays "blah":
thisTest.run();
// doesn't work; this is scoped to be the document so this.status is undefined:
$(document).ready(thisTest.run);
さて、この呼び出しを変更すると...
$(document).ready(thisTest.run.bind(thisTest));
...これは動作します。しかし、これはちょっと恐ろしいことです。つまり、ある状況下ではコードはすべてコンパイルできてうまく動作しますが、スコープをバインドするのを忘れると壊れてしまうのです。
私は、クラスを使用するときに "this" が何にスコープされているかを気にする必要がないように、クラス内でそれを行う方法を望みます。
何か提案はありますか?
更新情報
太い矢印を使うのも効果的な方法です。
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
それは有効な方法なのでしょうか?
どのように解決するのですか?
ここにはいくつかの選択肢があり、それぞれにトレードオフがあります。残念ながら、明らかな最適解はなく、アプリケーションに依存します。
自動クラスバインディング
ご質問の通りです。
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
-
良い/悪い: これは、クラスのインスタンスごとにメソッドごとに追加のクロージャを作成します。このメソッドが通常メソッド呼び出しでのみ使用される場合、これは過剰な要求です。しかし、コールバックの位置で多く使われるのであれば、クラスのインスタンスがキャプチャする方が効率的です。
this
コンテキストを取得する方が効率的です。 -
良い点: 外部呼び出し元が
this
コンテキスト - 良いですね。TypeScriptでのタイプセーフ
- 良い。関数にパラメータがある場合、余分な作業がない
-
悪い点 派生クラスは、この方法で書かれたベースクラスのメソッドを
super.
- 悪い点 どのメソッドが "pre-bound" で、どれがそうでないかの正確なセマンティクスは、あなたのクラスとその消費者の間に追加の非タイプセーフ契約を作成します。
関数.bind
また、図のように
$(document).ready(thisTest.run.bind(thisTest));
- 良い/悪い 最初の方法と比較して、メモリ/性能のトレードオフが反対になっている
- 良い点 関数にパラメータがある場合、余分な作業がない
- 悪い点 TypeScriptでは、これは現在、型安全性を持っていません。
- 悪い点 ECMAScript 5 でのみ使用可能。
- 悪い点 インスタンス名を 2 回入力する必要がある
太い矢印
TypeScriptの場合(ここでは説明のためにダミーのパラメータをいくつか付けて表示しています)。
$(document).ready((n, m) => thisTest.run(n, m));
- 良い/悪い 最初の方法と比較して、メモリ/性能のトレードオフが反対になっている
- 良い点: TypeScriptでは、100%の型安全性を持つ。
- 良い。ECMAScript 3 で動作する。
- 良い。インスタンス名を一度だけ入力する必要がある
- 悪い点 パラメータを2回入力する必要がある
- 悪い点 可変長のパラメータでは動作しない
関連
-
[解決済み】Typescriptで、! (エクスクラメーションマーク/バン)演算子でメンバを再参照するのは?
-
[解決済み] コールバック内で正しい `this` にアクセスする方法
-
[解決済み] Typescript は ?演算子をサポートしていますか?(そして、それは何と呼ばれているのでしょうか?)
-
[解決済み] [Solved] setTimeoutコールバックに正しい "this "コンテキストを渡すか?
-
[解決済み] describe'という名前が見つかりません。テストランナー用の型定義をインストールする必要がありますか?
-
[解決済み] 文字列ユニオンから文字列配列へ
-
[解決済み] tsc が `TS2307: Cannot find module` for a local file をスローします。
-
[解決済み] Visual Studio Code - インポート引用符の設定を調整する
-
[解決済み] グローバルスコープの拡張は、外部モジュールまたはアンビエントモジュール宣言にのみ直接ネストすることができます(2669)
-
[解決済み] モジュールと名前空間 - Import vs Require Typescript
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] TypeScriptの予約語 "type "とは何ですか?
-
[解決済み] Typescriptでインターフェースやクラスを使用する場合 [重複].
-
[解決済み] ユニオン型からインターセクション型への変換
-
[解決済み] Angular 2でアプリ起動時にサービスを実行する方法
-
[解決済み] 文字列ユニオンから文字列配列へ
-
[解決済み] tsc が `TS2307: Cannot find module` for a local file をスローします。
-
[解決済み] tsconfig.jsonのtargetは何のためにあるのですか?
-
[解決済み] TypeScriptでObject.keysがkeyof型を返さないのはなぜですか?
-
[解決済み] グローバルスコープの拡張は、外部モジュールまたはアンビエントモジュール宣言にのみ直接ネストすることができます(2669)
-
[解決済み] モジュールと名前空間 - Import vs Require Typescript