Javascript 如何避免硬编码?装修工

Javascript 如何避免硬编码?装修工,javascript,typescript,decorator,ecmascript-2016,Javascript,Typescript,Decorator,Ecmascript 2016,我已经阅读了很多资料,但是有一些我对装饰师也没能做到的事情 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(); foo

我已经阅读了很多资料,但是有一些我对装饰师也没能做到的事情

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(这个“bar”,arg)记录在控制台中
栏中

现在让我们使用一个装饰器:

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;
        }
    };
}
value.value.apply(this, args);
我们使用相同的功能,但经过修饰:

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");
对象
窗口
通过
console.log(此)记录在控制台中
foo

bar
从不被
foo
调用,因为
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;
        }
    };
}
value.value.apply(this, args);
如何保存原始
值?

我相信您可以使用

var self = this;

为了在该特定点保留“this”。然后,只需在稍后的点上使用
self
,您可能希望该
不使用箭头功能。使用函数表达式:

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

函数日志(目标:对象,键:字符串,描述符:TypedPropertyDescriptor-参见“示例-无参数>注释”下的“坏与好”示例)

感谢您尝试回答,但当使用装饰器时,我无法控制特定的点。感谢您的回答,我没有注意到我使用的是箭头函数。@是的,很容易出错。我没有注意到,直到我在操场上弹出它,看到javascript在做这件事时,
OP的代码似乎来自my博客文章--我会更新它的!:)我也有这个问题,在一个很好的例子中,一篇博客文章更新了内容!一个挑剔:似乎
目标
的类型应该是
对象
而不是
函数
,因为它是类的原型。