前言
裝飾器: 裝飾器是一種特殊類型聲明, 它能夠被附加到類聲明,方法,屬性或者參數上, 可以修改類的行為
通俗的講裝飾器就是一個方法, 可以注入到類,方法,屬性參數上來擴展類,屬性,方法,參數功能
常見的裝飾器:屬性裝飾器,方法裝飾器,參數裝飾器
寫法: 普通修飾器(無法傳參)、裝飾器工廠(可以傳參)
類修飾器
裝飾器在類聲明之前被執行,類裝飾器應用於類構造函數,可以用來監視,修改或者代替類定義
類普通裝飾器:
function logClass(params: any) { console.log(params); } @logClass class HttpClient{ constructor() { } getData() { } }
定義了一個 logClass 類 並且帶了一個默認參數 params
這個 params == HttpClinent
function logClass(params: any) { console.log(params); params.prototype.httpUrl = "http.xxxxx"; // 通過原型鏈添加一個 給類添加一個屬性 } @logClass class HttpClient{ constructor() { } getData() { } } var httpClient = new HttpClient(); console.log(httpClient.httpUrl);
運行結果:

通過 類裝飾器添加 方法
function logClass(params: any) { console.log(params); params.prototype.httpUrl = "http.xxxxx"; // 通過原型鏈添加一個 給類添加一個屬性 params.prototype.run = function() { console.log("run-app"); } } @logClass class HttpClient{ constructor() { } getData() { } } var httpClient = new HttpClient(); console.log(httpClient.httpUrl); httpClient.run(); // 執行通過裝飾器添加的方法
類裝飾器工廠:
function logClass(params: string) { console.log(params); // 傳入的參數類型 return function(tarage:any) { // tarage == HttpClient } } @logClass("傳入參數") class HttpClient{ constructor() { } getData() { } } var httpClient = new HttpClient();
如果是裝飾器工廠必須要寫入 參數 @logClass("傳入參數")
可以根據裝飾器傳入的參數去實現需要的功能
function logClass(params: string) { console.log(params); // 傳入的參數類型 return function(tarage:any) { // tarage == HttpClient tarage.prototype.apiUrl = params; // 通過原型鏈修改 類的屬性 } } @logClass("http://xxxxxx123") class HttpClient{ constructor() { } getData() { } } var httpClient = new HttpClient();
而且還可以重載 構造函數
function logClass(target: any) { console.log(target); return class extends target{ apiUrl:any="修改后的數據"; getData() { this.apiUrl = this.apiUrl + "---===--"; console.log(this.apiUrl); } } } @logClass class HttpClient{ public apiUrl: string | undefined; constructor() { this.apiUrl = "我是構造函數里面的apiUrl"; } getData() { console.log(this.apiUrl); } } var httpClient = new HttpClient(); console.log(httpClient.apiUrl) httpClient.getData();
屬性裝飾器
屬性裝飾器表達式會在運行時當作函數調用, 傳入2個參數
* 第一個參數:對於靜態成員來說 是類的構造函數, 對於實例化成員是類的原型對象
* 第二個參數:成員名字
function logProperty(params: any) { console.log("接收傳入的參數", params); return function(tarage: any, attr: any) { console.log("參數一:", tarage); // 對於實例化成員是類的原型對象 console.log("參數二:", attr);// 成員名字 } } class HttpClient{ @logProperty("test") public url:string|undefined; // 這個屬性使用 屬性裝飾器 constructor() { } getData() { } }
通過參數一 修改屬性值:
function logProperty(params: any) { console.log("接收傳入的參數", params); return function(tarage: any, attr: any) { console.log("參數一:", tarage); // 對於實例化成員是類的原型對象 console.log("參數二:", attr);// 成員名字 tarage[attr] = params; // 這里修改屬性值 } } class HttpClient{ @logProperty("test") public url:string|undefined; // 這個屬性使用 屬性裝飾器 constructor() { } getData() { console.log( "url屬性值", this.url); } } var httpClient = new HttpClient(); httpClient.getData(); // 輸出 url屬性值 test
方法裝飾器
它會被應用到方法的 屬性描述符上, 可以用來監視,修改或者替換方法定義
* 方法裝飾器會在運行時傳入3個參數
* 參數一: 對於靜態成員來說是類的構造函數,對於實例成員是類的原型
* 參數二: 成員名字
* 參數三: 成員的屬性描述符。
function logMethod(params:any) { console.log("調用傳入的參數", params) return function(tarage:any, methodName: string, desc:any){ console.log("參數一", tarage); // 實例成員是類的原型 console.log("參數二", methodName); // 成員名字, 方法名 console.log("參數三", desc); // 描述 } } class HttpClient{ public url:string|undefined; constructor() { } @logMethod("get") getData() { // 這個方法使用了 裝飾器 console.log( "url屬性值", this.url); } }
第一個參數是 實例成員的原型, 可以通過它給原型添加屬性或方法
function logMethod(params:any) { console.log("調用傳入的參數", params) return function(tarage:any, methodName: string, desc:any){ console.log("參數一", tarage); // 實例成員是類的原型 console.log("參數二", methodName); // 成員名字, 方法名 console.log("參數三", desc); // 描述 tarage.api = "我是裝飾器添加的 屬性"; tarage.run = function() { console.log("我是裝飾器添加的方法"); } } } class HttpClient{ public url:string|undefined; constructor() { } @logMethod("get") getData() { // 這個方法使用了 裝飾器 console.log( "url屬性值", this.url); } } var httpClient = new HttpClient(); console.log(httpClient.api); // 輸出: 我是裝飾器添加的 屬性 httpClient.run(); // 輸出 我是裝飾器添加的方法
第三個參數是 描述
修改裝飾器方法, 把裝飾器方法里面的所有參數修改為string類型
function logMethod(params:any) { console.log("調用傳入的參數", params) return function(tarage:any, methodName: string, desc:any){ console.log(desc.value); // 輸出 function() { console.log( "url屬性值", this.url);} var methodFun = desc.value; desc.value = function(...args:any) { // 重寫 getData 方法 args = args.map((value:any)=>{ return String(value); }); console.log(args); // 使用對象冒充, 還原之前的函數 methodFun.apply(this, args); // 執行輸出 我是getData方法 } } } class HttpClient{ public url:string|undefined; constructor() { } @logMethod("get") getData(...args:any) { // 這個方法使用了 裝飾器 console.log(args);// 輸出: Array(2) ["123", "adb"] console.log( "我是getData方法"); } } var httpclient = new HttpClient(); httpclient.getData(123, "adb"); // 輸出: Array(2) ["123", "adb"]
方法參數裝飾器
參數裝飾器表達式會在運行時當作函數調用,可以使用參數裝飾器為類的原型
增加一些元素數據,傳入三個參數:
參數一: 對於靜態成員來說是類的構造函數, 對於實例成員是類的原型對象
參數二:方法名稱
參數三:參數在函數參數列表中的索引
function logParams(params:any) { return function(target:any,methodName:any,paramsIndex:number){ console.log(params);// 我是裝飾器參數 console.log(target); // Object {getData: , constructor: } console.log(methodName); // getData console.log(paramsIndex);// 0 } } class HttpClient{ public url:string|undefined; constructor() { } getData(@logParams("我是裝飾器參數")uuid:any) { // 這個方法使用了 裝飾器 console.log(uuid); console.log( "我是getData方法"); } } var httpClinet = new HttpClient(); httpClinet.getData("test");
注意裝飾器的執行順序:
屬性裝飾器>方法裝飾器>方法參數裝飾器>類裝飾器
如果一個方法有兩個裝飾器, 那么 后面的裝飾器先執行,再到前面的
