9

「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は in によってコンソールに記録されconsole.log(this);ますfoo

文字列"FooBar {foo: function, bar: function} bar test"は in によってコンソールに記録されconsole.log(this, "bar", arg);ますbar

それでは、デコレータを使用しましょう。

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");

オブジェクトWindowは in によってコンソールに記録されconsole.log(this);ますfoo

Andは、cause causeによってbar呼び出されるfooことはありません。this.bar(arg);Uncaught TypeError: this.bar is not a function

問題は、デコレータthis内にハードコーディングされていることです:log

value.value.apply(this, args);

this元の値を保存するにはどうすればよいですか?

4

2 に答える 2

18

アロー関数を使用しないでください。関数式を使用します。

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 良い」の例を参照してください。

于 2015-05-19T16:00:33.027 に答える