Contact TS for a long time do not know what is decorator, decorator decoration is in what?
Next, record one of your learning processes:
// ts.config
"compilerOptions": {
"experimentalDecorators": true
}
</div>
Copy the code
Class decorator
-
Class decorators are declared before class declarations, applied to class constructors, and can monitor, modify, and replace class definitions, passing in an argument;
function logClz(params:any) { console.log(params) // class HttpClient } @logClz class HttpClient { constructor() { } } Copy the code
logClz()
Received parameterparams
That’s the class being decoratedHttpClient
- for
HttpClient
Dynamically extend properties properties and methods
function logClz(params:any) { params.prototype.url = 'xxxx'; params.prototype.run = function() { console.log('run... '); }; } var http:any = new HttpClient(); http.run(); // run...Copy the code
-
Decorator factory: closures that return functions that are the real decorators.
function logClz(params:string) { console.log('params:', params); //params: hello return function(target:any) { console.log('target:', target); //target: class HttpClient target.prototype.url = params; }} @logclz ('hello') class HttpClient {constructor() {}} var HTTP :any = new HttpClient(); console.log(http.url); //helloCopy the code
- When using a decorator factory, you can declare the parameters as optional if you don’t want to pass arguments to the decorator, but you still can’t lose the parentheses when using the decorator!
function logClz(params? :string) { return function(target:any) { } } @logClz() class HttpClient { constructor() { } }Copy the code
-
Overloaded constructor
- Class decorator expressions are called at run time as functions, with the constructor of the class as its only argument;
- If the class decorator returns a value, it replaces the class declaration with the provided constructor.
function logClz(target:any) { return class extends target { url = 'change url' getData() { console.log('getData:', this.url); } } } @logClz class HttpClient { public url:string|undefined; constructor() { this.url = 'init url' } getData() { console.log(this.url); } } var http = new HttpClient(); // The decorator returns a subclass of HttpClient, so TS can automatically derive the HTTP type http.getData(); //getData: change urlCopy the code
-
Modify the class definition
function fn<T extends {new(... args: any[]): {}}>(constructor: T): T { class Ps extends constructor { age: number = 20; // extend an attribute of type number age} return Ps; } @fn class Person{ } let p:any = new Person(); // The decorated Person has become Ps console.log(p.age) //20Copy the code
function fn(v: number) { return function<T extends {new(... args: any[]): {}}>(cst: T): T { class Ps extends cst { age: number = v; } } } @fn(10) class Person { } //age:number = 10 @fn(20) class Cat { } //age:number = 20Copy the code
T extends {new(… Args: any[]): {}} : {new(… Args: any[]): {}} is an object literal, equivalent to new(… Args: any[]) => {}, meaning a new function, return type {}
function identity<T>(arg: T): T { return arg; } let myIdentity: <U>(arg: U) => U = identity; Let myIdentity: {<T>(arg: T): T} = identity; {<T>(arg: T): T; } let myIdentity: GenericIdentityFn = identity;Copy the code
Attribute decorator
-
Property decorator expressions are called as functions at run time, passing in two arguments:
- Class constructor for static members, class prototype object for instance members;
- Member’s name;
function logProp(params:any) { return function(target:any, attr:any) { console.log(target) // { constructor:f, getData:f } console.log(attr) // url target[attr] = params; // Modify the property value with the prototype object = the argument passed by the decorator target. API = 'XXXXX '; Run = function() {// Extend method console.log('run... '); } } } class HttpClient { @logProp('http://baidu.com') public url:any|undefined; constructor() { } getData() { console.log(this.url); } } var http:any = new HttpClient(); http.getData(); // http://baidu.com console.log(http.api); // xxxxx http.run(); // run...Copy the code
Method decorator
-
Method decorators are applied to method property descriptors and can be used to monitor, modify, or replace method definitions.
-
The method decorator passes in three arguments at runtime:
- Class constructor for static members, class prototype object for instance members;
- Member’s name;
- Attribute descriptor for a member;
Function get(params:any) {console.log(params) // http://baidu.com return function(target:any, methodName:any, desc:any) { console.log(target) // { constructor:f, Log (methodName) // getData console.log(desc) // {value: ƒ, writable: true, enumerable: False, 64x: true} value, works without any additional control system. Var oldMethod = desc.value; //2\. Redefine method body desc. Value = function(... Args :any[]) {//3\. Let newArgs = args.map((item)=>{return String(item); }); OldMethod. Apply (this, newArgs); Oldmethod. call(this,... newArgs); } } } class HttpClient { constructor() { } @get('http://baidu.com') getData(... args:any[]) { console.log('getData: ', args); } } var http = new HttpClient(); http.getData(1, 2, true); // getData: ["1", "2", "true"]Copy the code
Method parameter decorator
-
The parameter decorator expression is called at run time to add some element data to the prototype of the class, passing in three arguments:
- Class constructor for static members, class prototype object for instance members;
- Method namesIf the constructor argument is decorated, the value is
undefined
- Parameter index in function parameter list;
Function logParams(params:any) {console.log(params) // uuid return function(target:any, methodName:any, paramIndex:any) { console.log(target) // { constructor:f, getData:f } console.log(methodName) // getData console.log(paramIndex) // 0 } } class HttpClient { constructor() { } getData(@logParams('uuid') uuid:any) { console.log(uuid); }}Copy the code
-
Note: Parameter decorators can only be used to monitor whether a method’s parameters are passed in;
-
Parameter decorators are widely used in Angular, especially in conjunction with the reflect-Metadata library to support the experimental Metadata API;
-
The return value of the parameter decorator is ignored.
Decorator execution order
-
Decorator composition: TS supports multiple decorators on a statement at the same time. Syntax is written from left to right or from top to bottom.
@f @g x @f @g x Copy the code
-
In TypeScript, when multiple decorators are applied to a declaration, the following steps occur:
- Evaluate decorator expressions from top to bottom;
- The result of the evaluation is called as a function from the bottom up.
-
The different decorators are executed in the following order: property decorator > method decorator > parameter decorator > class decorator
function logClz11(params:string) { return function(target:any) { console.log('logClz11') } } function logClz22(params? :string) { return function(target:any) { console.log('logClz22') } } function logAttr(params? :string) { return function(target:any, attrName:any) { console.log('logAttr') } } function logMethod(params? :string) { return function(target:any, methodName:any, desc:any) { console.log('logMethod') } } function logParam11(params? :any) { return function(target:any, methodName:any, paramIndex:any) { console.log('logParam11') } } function logParam22(params? :any) { return function(target:any, methodName:any, paramIndex:any) { console.log('logParam22') } } @logClz11('http://baidu.com') @logClz22() class HttpClient { @logAttr() public url:string|undefined; constructor() { } @logMethod() getData() { console.log('get data'); } setData(@logParam11() param1:any, @logParam22() param2:any) { console.log('set data'); } } // logAttr --> logMethod --> logParam22 --> logParam11 --> logClz22 --> logClz11Copy the code
Author: hellomyshadow links: www.jianshu.com/p/f4c961cbb… The copyright of the book belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.