javascript - Làm thế nào để tránh mã cứng this? trong Decorators
Tôi đã đọc "Cách triển khai một decorator trong TypeScript?" và nhiều nguồn khác nhưng có một số thứ mà tôi chưa thể làm được với decorators.
class FooBar {
public foo(arg): void {
console.log(this);
this.bar(arg);
}
private bar(arg) : void {
console.log(this, "bar", arg);
}
}
Nếu chúng ta gọi hàm foo:
var foobar = new FooBar();
foobar.foo("test");
Đối tượng FooBar được ghi vào console bởi console.log(this); trong foo
Chuỗi "FooBar {foo: function, bar: function} bar test" được ghi vào console bởi console.log(this, "bar", arg); trong bar.
Bây giờ hãy sử dụng một decorator:
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;
}
};
}
Chúng tôi sử dụng cùng một hàm nhưng được trang trí:
class FooBar {
@log
public foo(arg): void {
console.log(this);
this.bar(arg);
}
@log
private bar(arg) : void {
console.log(this, "bar", arg);
}
}
Và chúng ta gọi foo như trước đây:
var foobarFoo = new FooBar();
foobarFooBar.foo("test");
Đối tượng Window được ghi vào bảng điều khiển bởi console.log(this); trong foo
Và bar không bao giờ được foo gọi vì this.bar(arg); gây ra Uncaught TypeError: this.bar is not a function.
Vấn đề là this được mã cứng bên trong decorator log:
value.value.apply(this, args);
Làm thế nào tôi có thể bảo toàn giá trị this gốc?
Câu trả lời #1
Đừng sử dụng hàm mũi tên. Hãy sử dụng biểu thức hàm:
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;
}
};
}
Theo cách đó, nó sẽ sử dụng ngữ cảnh this của hàm thay vì giá trị của this khi log được gọi.
Nhân tiện, tôi khuyên bạn nên chỉnh sửa tham số descriptor/value và trả về nó thay vì ghi đè bằng cách trả về một descriptor mới. Bằng cách đó, bạn giữ được các thuộc tính hiện có trong descriptor và sẽ không ghi đè những gì một decorator khác có thể đã làm với descriptor:
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;
}
Thêm chi tiết trong câu trả lời này - Xem ví dụ "Tệ vs Tốt" dưới "Ví dụ - Không có đối số > Ghi chú"
