上次學習了一下typecirpt-ioc
項目,一個優秀的IOC
容器,那個項目中用到了TypeScript
註解,反正比我寫的容器高級多了。是時候學習一下TypeScript
註解了。web
在WebStorm
環境下創建一個示例項目,試了一下,報錯。typescript
Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
json
對裝飾器的實驗性支持是一個在將來版本中可能會發生變化的特性,請設置xxx
選項以移除該警告。瀏覽器
編譯器所說的裝飾器,其實就是咱們所說的註解。看這個提示,應該是目前還不支持註解,仍是在試驗階段。咦?那爲何Angular
啓用了註解呢?閉包
後來查到了這張圖:app
主流瀏覽器全面支持ES5
,因此咱們不管用AngularJS
的原生JavaScript
開發也好,用Angular
、React
的TypeScript
開發也好,最後到瀏覽器執行的代碼都是ES5
腳本。框架
咱們應該認識下面三個圈,ES5
,ES6
涵蓋了ES5
並擴充了類與模塊,TypeScript
又是ES6
的超集。函數
最外圍的AtScript
由Google AtScript
團隊提出,對TypeScript
又進行了擴充,支持註解與introspection
(這個不知道是啥,百度翻譯是「自我檢討」,水平不夠不敢隨便翻譯)。學習
Google AtScript
團隊已經將註解
做爲ES7
的提案。可是通過測試,ES7
環境下還不支持註解,多是草案沒有經過?測試
後來,Google AtScript
與Microsoft
合做:
We’re excited to announce that we have converged the TypeScript and AtScript languages, and that Angular 2, the next version of the popular JavaScript library for building web sites and web apps, will be developed with TypeScript.
咱們很高興:咱們已經融合了TypeScript
和AtScript
,而且Angular 2
將採用TypeScript
來開發。
這就是咱們的Angular
。一樣是TypeScript
,咱們能夠像Spring
中同樣去加註解,而不須要像React
同樣去繼承。
class ShoppingList extends React.Component { render() { return ( <div className="shopping-list"> <h1>Shopping List for {this.props.name}</h1> <ul> <li>Instagram</li> <li>WhatsApp</li> <li>Oculus</li> </ul> </div> ); } }
新建tsconfig.json
文件,將compilerOptions
中的experimentalDecorators
設置爲true
,以忽略警告。
註解(裝飾器)是一類特殊類型的聲明,能夠用在類、方法、構造器、屬性和參數上。
其實本質上,定義一個註解,就是定義一個TypeScript
方法,只是該方法必須符合官方的規範。
定義兩個方法hello
和world
方法,兩個方法分別返回符合規範的函數閉包,參數target
、propertyKey
、descriptor
。經測試,這三個參數中target
和propertyKey
是必須的,沒有的話編譯過不去,descriptor
能夠省略。
function hello() { console.log("hello(): 加載."); return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log("hello(): 執行."); } } function world() { console.log("world(): 加載."); return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log("world(): 執行."); } } class Main { @hello() @world() method() { console.log('method(): 執行.'); } }
編譯、執行:
註解方法在編譯期間執行。註解方法加載從上到下,閉包功能執行從下到上。
打印三個參數的結果,具體含義在下面的方法註解一欄中講解。
類註解應用於類的構造函數,能夠使用它去觀察、修改或替換類的定義。類註解不能在聲明文件中被使用,或其餘ambient context
中使用。
class Person { message: string; constructor(message: string) { this.message = message; } greet() { console.log(`Hello ${this.message} !`); } } const person = new Person('World'); person.greet();
使用類註解,咱們能夠覆蓋原來的構造函數,因此依賴注入可能就是用這種方式實現的。
function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) { return class extends constructor { message = 'Decorator'; } } @classDecorator class Person { message: string; constructor(message: string) { this.message = message; } greet() { console.log(`Hello ${this.message} !`); } } const person = new Person('World'); person.greet();
覆蓋掉了原來的構造函數。
方法註解應用於方法的屬性描述器,也能夠觀察、修改替換方法定義。方法註解不能在聲明文件中被使用,或者是方法重載,或其餘ambient context
中使用。
class Person { message: string; constructor(message: string) { this.message = message; } greet() { console.log(`Hello ${this.message} !`); } } const person = new Person('World'); for (const property in person) { console.log(property); }
for in person
對象,遍歷出了message
和greet
。
function enumerable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = value; }; } class Person { message: string; constructor(message: string) { this.message = message; } @enumerable(false) greet() { console.log(`Hello ${this.message} !`); } } const person = new Person('World'); for (const property in person) { console.log(property); }
添加方法註解,@enumerable
,將該方法設置爲不可枚舉。
遍歷時就沒有greet
了,恕我直言,我以爲這個屬性描述器好像沒什麼用。
身體抱恙,頭腦混亂,如有錯誤之處歡迎指出,還有一個利用反射實現的屬性裝飾器,之後再與你們詳述。
工程要的是經驗,框架要的是功底。你喜歡哪個?