javascript - デコレーターでこのハードコーディングを避ける方法
私は「TypeScriptデコレーターをどのように実装するか?」や複数の情報源を読みましたが、デコレーターではまだできないことがあります。
class FooBar {
public foo(arg): void {
console.log(this);
this.bar(arg);
}
private bar(arg) : void {
console.log(this, "bar", arg);
}
}
もし私たちが関数fooを呼び出すと:
var foobar = new FooBar();
foobar.foo("test");
オブジェクト FooBar は foo 内の console.log(this); によってコンソールに記録されます
文字列 "FooBar {foo: function, bar: function} bar test" は、bar 内の console.log(this, "bar", arg); によってコンソールにログ出力されます。
それではデコレーターを使いましょう。
function log(target: Function, key: string, value: any) {
return {
value: (...args: any[]) => {
var a = args.map(a => JSON.stringify(a)).join();
var result = value.value.apply(this, args); // How to avoid hard coded this?
var r = JSON.stringify(result);
console.log(`Call: ${key}(${a}) => ${r}`);
return result;
}
};
}
私たちは同じ関数を使用しますが、デコレーションされています:
class FooBar {
@log
public foo(arg): void {
console.log(this);
this.bar(arg);
}
@log
private bar(arg) : void {
console.log(this, "bar", arg);
}
}
そして、以前と同じようにfooを呼び出します:
var foobarFoo = new FooBar();
foobarFooBar.foo("test");
foo 内で console.log(this); によってオブジェクト Window がコンソールに記録されます
そして bar は foo によって決して呼び出されません。なぜなら this.bar(arg); が Uncaught TypeError: this.bar is not a function を引き起こすからです。
問題は、log デコレーター内のハードコーディングされた this です:
value.value.apply(this, args);
元の this 値をどのように保持できますか?
回答 #1
アロー関数を使わないでください。関数式を使ってください:
function log(target: Object, key: string, value: any) {
return {
value: function(...args: any[]) {
var a = args.map(a => JSON.stringify(a)).join();
var result = value.value.apply(this, args);
var r = JSON.stringify(result);
console.log(`Call: ${key}(${a}) => ${r}`);
return result;
}
};
}
そうすることで、logが呼ばれたときのthisの値ではなく、関数のthisコンテキストが使われます。
ちなみに、ディスクリプタの値パラメータを編集して、それを返すことをお勧めします。新しいディスクリプタを返して上書きするのではなく。その方法で、現在ディスクリプタにあるプロパティを保持し、別のデコレーターがディスクリプタに行った変更を上書きすることを避けられます:
function log(target: Object, key: string, descriptor: TypedPropertyDescriptor<any>) {
var originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
var a = args.map(a => JSON.stringify(a)).join();
var result = originalMethod.apply(this, args);
var r = JSON.stringify(result);
console.log(`Call: ${key}(${a}) => ${r}`);
return result;
};
return descriptor;
}
この回答の詳細については、「例 - 引数なし > ノート」の下にある「悪い例 vs 良い例」を参照してください
