9

我已阅读“如何实现打字稿装饰器?” 和多个来源,但有些东西我也无法用装饰器做。

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

并且bar永远不会被foo因为this.bar(arg);Causes调用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;
        }
    };
}

这样,它将使用函数的this上下文而不是this调用 log 时的值。


顺便说一句,我建议编辑描述符/值参数并返回它,而不是通过返回一个新的描述符来覆盖它。这样你就可以保留当前描述符中的属性,并且不会覆盖另一个装饰器可能对描述符所做的事情:

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;
}

此答案中的更多详细信息- 请参阅“示例 - 无参数 > 注释”下的“坏与好”示例

于 2015-05-19T16:00:33.027 回答
0

我相信你可以使用

var self = this;

为了在那个特定点保留“这个”。然后,只需self在稍后你想要那个特定的地方使用this

于 2015-05-19T15:31:01.577 回答