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

Rem*_*sen 8 javascript decorator typescript ecmascript-7

我读过"如何实现打字稿装饰器?" 和多个来源,但我有一些东西,也没有能够与装饰.

class FooBar {
    public foo(arg): void { 
        console.log(this);
        this.bar(arg);
    }
    private bar(arg) : void { 
        console.log(this, "bar", arg);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我们调用函数foo:

var foobar = new FooBar();
foobar.foo("test"); 
Run Code Online (Sandbox Code Playgroud)

该对象FooBarconsole.log(this);in 登录到控制台中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;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

我们使用相同的功能,但装饰:

class FooBar {
    @log
    public foo(arg): void { 
        console.log(this);
        this.bar(arg);
    }
    @log
    private bar(arg) : void { 
        console.log(this, "bar", arg);
    }
}
Run Code Online (Sandbox Code Playgroud)

foo我们像以前一样调用:

var foobarFoo = new FooBar();
foobarFooBar.foo("test");
Run Code Online (Sandbox Code Playgroud)

该对象Windowconsole.log(this);in 登录到控制台中foo

并且bar永远不会foo因为this.bar(arg);原因而被调用Uncaught TypeError: this.bar is not a function.

问题是装饰者this内部的硬编码log:

value.value.apply(this, args);
Run Code Online (Sandbox Code Playgroud)

我怎样才能保存原始this价值?

Dav*_*ret 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;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

这样它将使用函数的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;
}
Run Code Online (Sandbox Code Playgroud)

此答案中的更多详细信息 - 请参阅"示例 - 没有参数>注释"下的"Bad vs Good"示例

  • OP的代码似乎来自我的博客文章 - https://smellegantcode.wordpress.com/2015/04/02/typescript-1-5-get-the-decorators-in/ - 我会更新它!:) (4认同)