如何避免硬编码?在装饰者

时间:2015-05-19 15:25:07

标签: javascript typescript decorator ecmascript-7

我已经阅读了"How to implement a typescript decorator?"和多个来源,但我有一些东西,也没有能够用装饰器。

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

中的console.log(this);在控制台中记录了对象foo

"FooBar {foo: function, bar: function} bar test"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

中的console.log(this);在控制台中记录了对象foo

bar永远不会调用foo,因为this.bar(arg);会导致Uncaught TypeError: this.bar is not a function

问题是this装饰器中的硬编码log

value.value.apply(this, args);

如何保存原始this值?

2 个答案:

答案 0 :(得分:17)

不要使用箭头功能。使用函数表达式:

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的值。

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

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

More details in this answer - 请参阅“示例 - 没有参数&gt;注释”下的“Bad vs Good”示例

答案 1 :(得分:0)

我相信你可以使用

var self = this;

为了在特定点保留'this'。然后,只需在稍后您需要特定self

的位置使用this