デコレータは主にクラスと組み合わせて使用されます
デコレータは、1つのタイプのデコレータ、2つの属性のデコレータ、3つのメソッドのデコレータ、4つのメソッドのパラメータのデコレータに分けられます。
クラスデコレータ
クラスデコレータの簡単な使用
// 类装饰器 params 指的是类本身,在浏览器中打印出来就是构造函数本身
function logClass (params: any) {
console.log(params)
}
@logClass
class HttpClient {
apiUrl:string;
constructor(apiUrl:string) {
this.apiUrl = apiUrl
}
}
クラスデコレータに属性とメソッドを追加します
// 装饰器
function logClass(params: any) {
// 放到构造函数的原型上
params.prototype.method = 'POST';
params.prototype.setMethod = (value: 'POST' | 'GET') => {
params.prototype.method = value;
};
}
// 装饰器的使用
@logClass
class HttpClient {
apiUrl: string;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
}
const http1:any = new HttpClient('xxxx');
console.log(http1.apiUrl) // xxxx
console.log(http1.method) // POST
http1.setMethod('GET')
console.log(http1.method) // GET
クラスデコレータファクトリ(デコレータ関数にパラメータを渡すことができます)
logclassFunction関数呼び出しによって返される関数は実際のクラスデコレータである
ため、logClassFunctionは単なるクラスデコレータファクトリであり、クラスデコレータ(つまり、返される関数)を生成するために使用されます。
// 装饰器工厂
function logClassFunction(slefArgus: {
name: string; age: number }) {
console.log(slefArgus);
return (params: any) => {
params.prototype.method = 'POST';
params.prototype.setMethod = (value: 'POST' | 'GET') => {
params.prototype.method = value;
};
params.prototype.data = slefArgus;
};
}
// 装饰器工厂函数的调用方式
@logClassFunction({
name: 'dx', age: 18 })
class HttpClient {
apiUrl: string;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
}
const http1: any = new HttpClient('xxxxx');
console.log(http1.apiUrl); // xxxx
console.log(http1.method); // POST
http1.setMethod('GET');
console.log(http1.method); // GET
console.log(http1.data); // {name: 'dx',age:18}
クラスデコレータオーバーライドクラス
クラスデコレータは、クラス自体のプロパティとメソッドが置き換えられるようにクラスを書き換えることができますが、必要なすべてのプロパティとメソッドを書き換える必要があります。そうしないと、型エラーが報告されます。
function reLogClass(targets: any) {
// 返回一个新的class 扩展 targets (targets就是被重构的类)
return class extends targets {
apiUrl: string = '这是重构的url';
getData() {
return {
url: this.apiUrl,
};
}
};
}
@reLogClass
class HttpClient {
apiUrl: string;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
}
const http1: any = new HttpClient('xxxxx');
console.log(http1.apiUrl); //这是重构的url
console.log(http1.getData()); // {url: '这是重构的url'}
HttpClientクラスのコンテンツはデコレータによって再構築されるため、出力されるapiurl属性は、デコレータ関数によって返されるクラスに基づいています。
属性デコレータ
属性デコレータは、クラス内の属性を変更するために使用されます。属性を変更するため、パラメータを渡す必要があります。ご存知のとおり、デコレータファクトリを使用する必要があります。クラスデコレータファクトリとは異なり、属性デコレータファクトリプロパティデコレータのみを返します(すべてメソッドを返します)。
function logProperty(params: string) {
return (targets: any, attr: string) => {
console.log(params, targets, attr);
// targets是 constructor attr是属性的名称(apiUrl), params是传过来的参数(这是属性装饰器)
// 这只能设置到原型上
targets[attr] = params;
};
}
class HttpClient {
@logProperty('这是属性装饰器')
apiUrl: string | undefined;
constructor() {
}
}
const http1 = new HttpClient();
console.log(http1.apiUrl); // 这是属性装饰器
私のテストによると、属性デコレータのパラメータを介して設定できるのはプロトタイプの値のみであるため、属性デコレータはデフォルト値しか設定できません。
オブジェクトインスタンスにそのような値がない場合は、プロトタイプに戻ってそれを見つけることは誰もが知っています。この値がインスタンスオブジェクトに存在する場合、プロトタイプでは検索されません(つまり、デコレータによって設定されたプロトタイプの値は無効です)。
インスタンスの値が存在する場合
function logProperty(params: string) {
return (targets: any, attr: string) => {
console.log(params, targets, attr);
// targets是 constructor attr是属性的名称(apiUrl), params是传过来的参数(这是属性装饰器)
// 这只能设置到原型上
targets[attr] = params;
};
}
class HttpClient {
@logProperty('这是属性装饰器')
apiUrl: string | undefined = "xxxx";
constructor() {
}
}
const http1 = new HttpClient();
console.log(http1.apiUrl); // xxxx
メソッドデコレータ
装飾された方法を置き換える
function logFunction(params: any) {
return function (construct: any, functionName: string, functionDesc: any) {
// construct 对于静态成员来说 是类的构造函数 对于实例成员是类的原型对象。
// functionName 是方法的名字
// functionDesc 是关于方法的一些描述 (一般不用,里面主要是是否可配置configurable 是否可数 enumerable 是否可写 writable 等)
console.log(construct, functionName, functionDesc);
// 将原先方法替换掉
functionDesc.value = () => {
return {
relUrl: params,
};
};
// 对原来的方法进行修改
};
}
class HttpClient {
apiUrl: string;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
@logFunction('xxxxx')
getData() {
return {
url: this.apiUrl,
};
}
}
const http1 = new HttpClient('www.baidu.com');
console.log(http1.getData()) // {relUrl: "xxxxx"}
装飾された方法を変更する
function logFunction(params: any) {
return function (construct: any, functionName: string, functionDesc: any) {
// construct 对于静态成员来说 是类的构造函数 对于实例成员是类的原型对象。
// functionName 是方法的名字
// functionDesc 是关于方法的一些描述 (一般不用,里面主要是是否可配置configurable 是否可数 enumerable 是否可写 writable 等)
console.log(construct, functionName, functionDesc);
const oMethod = functionDesc.value;
// 对原来的方法进行修改
functionDesc.value = function (newUrl: string, method: string) {
// 采用对象冒充,改变this,并将参数传入
oMethod.call(this, newUrl, method);
return {
url: newUrl,
method,
};
};
};
}
class HttpClient {
apiUrl: string;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
@logFunction('xxxxx')
getData(newUrl: string, method: string) {
console.log(`${
newUrl}原先`);
}
}
const http1 = new HttpClient('www.baidu.com');
console.log(http1.getData('www.taobao.com', 'get'));
// www.taobao.com原先
// {url: "www.taobao.com",method: "get"}
// tips: 从最终打印的结果可以发现,原先的方法也被执行了。
メソッドパラメータデコレータ
メソッドパラメータデコレータは通常使用されませんが、それが実現できる機能は他のデコレータでも実現できます。
function logAruguments(params: any) {
return (target: any, methodName: string, paramsIndex: number) => {
console.log(params, target, methodName, paramsIndex);
// target 对于静态成员来说 是类的构造函数 对于实例成员是类的原型对象。
// methodName 参数所在方法的名称
// paramsIndex 参数所在方法参数的下标
target.method = params;
};
}
class HttpClient {
apiUrl: string;
method: string | undefined;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
getData(@logAruguments('post') method: string) {
return {
url: this.apiUrl,
method: this.method || method,
};
}
}
const http1 = new HttpClient('xxxxx');
console.log(http1.getData('get'));
// {url: "xxxxx", method: "post"}
// 因为在方法参数装饰器中给this.method赋值了,所以打印出来不是get
デコレータの実行順序
実際の使用では、複数のデコレータを一緒に使用できます。
公式ウェブサイトでのデコレータの実行順序の説明
クラス内のさまざまな宣言のデコレータは、以下に指定された順序で適用されます。
パラメータデコレータ、次にメソッドデコレータ、アクセサデコレータ、または属性デコレータが各インスタンスメンバーに適用されます。
パラメータデコレータ、次にメソッドデコレータ、アクセサデコレータ、または属性デコレータが各静的メンバーに適用されます。
パラメータデコレータがコンストラクタに適用されます。
クラスデコレータがクラスに適用されます。
パラメータデコレータ>メソッドデコレータ>メソッドパラメータデコレータ>クラスデコレータ
各タイプのデコレータが複数ある場合は、後ろから前、右から左の順に実行します。