如何避免对此进行硬编码?在装饰器中
How to avoid hard coded this? in Decorators
我已阅读 和多个来源,但有些事情我无法使用装饰器来完成。
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
.
问题是 log
装饰器中的硬编码 this
:
value.value.apply(this, args);
如何保存原始 this
值?
我相信你可以使用
var self = this;
为了在那个特定点保留 '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
的值。
顺便说一下,我建议编辑 descriptor/value 参数和 return 而不是通过 return 新的描述符覆盖它。这样您就可以将属性当前保存在描述符中,并且不会覆盖另一个装饰器可能对描述符所做的操作:
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;
}
- 请参阅 "Example - Without Arguments > Notes"
下的 "Bad vs Good" 示例
我已阅读
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
.
问题是 log
装饰器中的硬编码 this
:
value.value.apply(this, args);
如何保存原始 this
值?
我相信你可以使用
var self = this;
为了在那个特定点保留 '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
的值。
顺便说一下,我建议编辑 descriptor/value 参数和 return 而不是通过 return 新的描述符覆盖它。这样您就可以将属性当前保存在描述符中,并且不会覆盖另一个装饰器可能对描述符所做的操作:
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;
}