摘要:值得注意的是,的返回值復寫了原始的構造函數,原因是類裝飾器必須返回一個構造器函數。原始構造函數的原型被復制給的原型,以確保在創建一個的新實例時,操作符如愿以償,具體原因可參考鄙人另一篇文章原型與對象。
上一篇文章中,我們討論了TypeScript源碼中關于方法裝飾器的實現,搞明白了如下幾個問題:
裝飾器函數是如何被調用的?
裝飾器函數參數是如何傳入的?
__decorate函數干了些什么事情?
接下來我們繼續屬性裝飾器的觀察。
屬性裝飾器屬性裝飾器的聲明標識如下:
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
如下我們為一個類的屬性添加了一個名為@logProperty的裝飾器
class Person { @logProperty public name: string; public surname: string; constructor(name : string, surname : string) { this.name = name; this.surname = surname; } }
上一篇解釋過,當這段代碼最后被編譯成JavaScript執行時,方法__decorate會被調用,但此處會少最后一個參數(通過Object. getOwnPropertyDescriptor屬性描述符)
var Person = (function () { function Person(name, surname) { this.name = name; this.surname = surname; } __decorate( [logProperty], Person.prototype, "name" ); return Person; })();
需要注意的是,這次TypeScript編譯器并沒像方法裝飾器那樣,使用__decorate返回的結果覆蓋原始屬性。原因是屬性裝飾器并不需要返回什么。
Object.defineProperty(C.prototype, "foo", __decorate( [log], C.prototype, "foo", Object.getOwnPropertyDescriptor(C.prototype, "foo") ) );
那么,接下來具體實現這個@logProperty裝飾器
function logProperty(target: any, key: string) { // 屬性值 var _val = this[key]; // getter var getter = function () { console.log(`Get: ${key} => ${_val}`); return _val; }; // setter var setter = function (newVal) { console.log(`Set: ${key} => ${newVal}`); _val = newVal; }; // 刪除屬性 if (delete this[key]) { // 創建新的屬性 Object.defineProperty(target, key, { get: getter, set: setter, enumerable: true, configurable: true }); } }
實現過程首先聲明了一個變量_val,并用所裝飾的屬性值給它賦值(此處的this指向類的原型,key為屬性的名字)。
接著聲明了兩個方法getter和setter,由于函數是閉包創建的,所以在其中可以訪問變量_val,在其中可以添加額外的自定義行為,這里添加了將屬性值打印在控制臺的操作。
然后使用delete操作符將原屬性從類的原型中刪除,不過需要注意的是:如果屬性存在不可配置的屬性時,這里if(delete this[key])會返回false。而當屬性被成功刪除,方法Object.defineProperty()將創建一個和原屬性同名的屬性,不同的是新的屬性getter和setter方法,使用上面新創建的。
至此,屬性裝飾器的實現就完成了,運行結果如下:
var me = new Person("Remo", "Jansen"); // Set: name => Remo me.name = "Remo H."; // Set: name => Remo H. name; // Get: name Remo H.類裝飾器
類裝飾器的聲明標識如下:
declare type ClassDecorator =(target: TFunction) => TFunction | void;
可以像如下方式使用類裝飾器:
@logClass class Person { public name: string; public surname: string; constructor(name : string, surname : string) { this.name = name; this.surname = surname; } }
和之前不同的是,經過TypeScript編譯器編譯為JavaScript后,調用__decorate函數時,與方法裝飾器相比少了后兩個參數。僅傳遞了Person而非Person.prototype。
var Person = (function () { function Person(name, surname) { this.name = name; this.surname = surname; } Person = __decorate( [logClass], Person ); return Person; })();
值得注意的是,__decorate的返回值復寫了原始的構造函數,原因是類裝飾器必須返回一個構造器函數。接下來我們就來實現上面用到的類裝飾器@logClass:
function logClass(target: any) { // 保存對原始構造函數的引用 var original = target; // 用來生成類實例的方法 function construct(constructor, args) { var c : any = function () { return constructor.apply(this, args); } c.prototype = constructor.prototype; return new c(); } // 新的構造函數 var f : any = function (...args) { console.log("New: " + original.name); return construct(original, args); } // 復制原型以便`intanceof`操作符可以使用 f.prototype = original.prototype; // 返回新的構造函數(會覆蓋原有構造函數) return f; }
這里實現的構造器中,聲明了一個名為original的變量,并將所裝飾類的構造函數賦值給它。接著聲明一個工具函數construct,用來創建類的實例。然后定義新的構造函數f,在其中調用原來的構造函數并將初始化的類名打印在控制臺,當然我們也可以添加一些其他自定義的行為。
原始構造函數的原型被復制給f的原型,以確保在創建一個Person的新實例時,instanceof操作符如愿以償,具體原因可參考鄙人另一篇文章原型與對象。
至此類裝飾器的實現就完成了,可以驗證下:
var me = new Person("Remo", "Jansen"); // New: Person me instanceof Person; // true
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/101520.html
摘要:可見參數裝飾器函數需要個參數被裝飾類的原型,裝飾參數所屬的方法名,參數的索引。參數裝飾器不應當用來修改構造器方法或屬性的行為,它只應當用來產生某種元數據。一旦元數據被創建,我們便可以用其它的裝飾器去讀取它。 之前已經分別介紹了方法裝飾器、屬性裝飾器和類裝飾器,這篇文章我們來繼續關注這些話題: 參數裝飾器 裝飾器工廠 我們將圍繞以下這個例子,來探討這些概念: class Person...
摘要:使用裝飾器的方法很簡單在裝飾器名前加字符,寫在想要裝飾的方法上,類似寫注釋的方式裝飾器實際上是一個函數,入參為所裝飾的方法,返回值為裝飾后的方法。經過裝飾過的方法,它依然按照原來的方式執行,只是額外執行了附件的裝飾器函數的功能。 讓我來深入地了解一下TypeScript對于裝飾器模式的實現,以及反射與依賴注入等相關特性。 在Typescript的源代碼中,可以看到裝飾器能用來修飾cla...
摘要:慶幸的是,已經支持反射機制,來看看這個特性吧元數據反射可以通過安裝包來使用元數據反射的若要使用它,我們需要在中設置為,同時添加的引用,同時加載文件。復雜類型序列化的團隊為復雜類型的元數據序列化做出了努力。 本篇內容包括如下部分: 為什么JavaScript中需要反射 元數據反射API 基本類型序列化 復雜類型序列化 為什么JavaScript中需要反射? 關于反射的概念,摘自百度百...
摘要:本文從裝飾模式出發,聊聊中的裝飾器和注解。該函數的函數名。不提供元數據的支持。中的元數據操作可以通過包來實現對于元數據的操作。 ??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經常看到類似于java spring中注解的寫法。本文從裝飾模式出發,聊聊Typescipt中的裝飾器和注解。 什么是裝飾者模式 Typescript中的裝飾器 Typescr...
摘要:看了這一章,發現原來是裝飾器,又一新知識。期間,裝飾器會做一些額外的工作。書中介紹了模塊中的三個裝飾器。另一個是,這個裝飾器把函數結果保存了起來,避免傳入相同參數時重復計算。疊放不奇怪,裝飾器返回的就是函數或可調用對象。 在 Web 框架 Flask 中,最常看到的或許是以@app.route開頭的那行代碼。由于還是剛接觸 Flask,所以對這種語法還不熟悉。看了這一章,發現原來是裝飾...
閱讀 834·2023-04-26 00:13
閱讀 2836·2021-11-23 10:08
閱讀 2455·2021-09-01 10:41
閱讀 2121·2021-08-27 16:25
閱讀 4205·2021-07-30 15:14
閱讀 2367·2019-08-30 15:54
閱讀 867·2019-08-29 16:22
閱讀 2744·2019-08-26 12:13