如何避免硬编码?在装饰器中

Posted

技术标签:

【中文标题】如何避免硬编码?在装饰器中【英文标题】:How to avoid hard coded this? in Decorators 【发布时间】:2015-07-31 12:42:31 【问题描述】:

我已经阅读了 "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"); 

对象FooBarconsole.log(this);foo中记录到控制台

console.log(this, "bar", arg); 将字符串 "FooBar foo: function, bar: function bar test" 记录在控制台中,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");

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

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

问题在于log 装饰器内部的硬编码this

value.value.apply(this, args);

如何保存原来的this 值?

【问题讨论】:

【参考方案1】:

相信你可以使用

var self = this;

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

【讨论】:

感谢您尝试回答,但使用装饰器时,我无法控制特定点【参考方案2】:

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

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;

More details in this answer - 请参阅“示例 - 无参数 > 注释”下的“坏与好”示例

【讨论】:

感谢您的回答,我没有注意到我正在使用箭头函数。 @OweRReLoaDeD 是的,很容易错过。直到我在操场上弹出它并看到 javascript 正在执行 _this 时我才注意到 OP 的代码似乎来自我的博客文章 - smellegantcode.wordpress.com/2015/04/02/… - 我会更新它! :) 我也有这个问题儿子在blog.wolksoftware.com/…blog.wolksoftware.com/…更新了一篇博文 很好的例子!一个挑剔:似乎target 的类型应该是Object 而不是Function,因为它是类的原型。

以上是关于如何避免硬编码?在装饰器中的主要内容,如果未能解决你的问题,请参考以下文章

python中装饰器修复技术

Python3中装饰器介绍

Python编程系列---Python中装饰器的几种形式及万能装饰器

Python中装饰器(转)

php中装饰器的完整继承行为

对Python中装饰器(Decorator)的理解与进阶