javascript - 如何避免对此进行硬编码?在装饰器中

标签 javascript typescript decorator ecmascript-2016

我已阅读 "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

字符串 "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");

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

bar从未被 foo 调用因为this.bar(arg);原因Uncaught TypeError: this.bar is not a function .

问题是硬编码的thislog里面装饰者:

value.value.apply(this, args);

我怎样才能保存原件 this值(value)?

最佳答案

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

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 - 请参阅“示例 - 无参数 > 注释”下的“坏与好”示例

关于javascript - 如何避免对此进行硬编码?在装饰器中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30329832/

相关文章:

javascript - JS-Math.atan(y/x) x==0

javascript - 谷歌条形图条形颜色没有改变

c++ - 具有非虚拟成员的类的装饰器

validation - 将输入类型编号限制为 Angular 2 中的小数点后 2 位

python - 用 Python 装饰整个库

Python,如何添加另一个装饰器来过滤具有Python属性的现有多重装饰器的输出?

JavaScript setInterval 函数替代

JavaScript : casting int to char trouble

javascript - 如何将 TypeScript 转换为 ES6?

typescript - moment.js 如何用 typescript 导入?