裝飾器(Decorator)可聲明在類及其成員(例如屬性、方法等)之上,為它們提供一種標注,用于分離復(fù)雜邏輯或附加額外邏輯,其語法形式為@expression。expression是一個會在運行時被調(diào)用的函數(shù),它的參數(shù)是被裝飾的聲明信息。假設(shè)有一個@sealed裝飾器,那么可以像下面這樣定義sealed()函數(shù)。
          function sealed(target) { //... }

            有兩種方式可以開啟裝飾器,第一種是在輸入命令時添加--experimentalDecorators參數(shù),如下所示,其中--target參數(shù)不能省略,它的值為“ES5”。
          tsc default.ts --target ES5 --experimentalDecorators
            第二種是在tsconfig.json配置文件中添加experimentalDecorators屬性,如下所示,對應(yīng)的target屬性也不能省略。
          { compilerOptions: { target: "ES5", experimentalDecorators: true } }
          一、類裝飾器


            類裝飾器用于監(jiān)聽、修改或替換類的構(gòu)造函數(shù),并將其作為類裝飾器唯一可接收的參數(shù)。當裝飾器返回undefined時,延用原來的構(gòu)造函數(shù);而當裝飾器有返回值時,會用它來覆蓋原來的構(gòu)造函數(shù)。下面的示例會通過類裝飾器封閉類的構(gòu)造函數(shù)和原型,其中@sealed聲明在類之前。
          @sealed class Person { name: string; constructor(name: string) { this.name =
          name; } } functionsealed(constructor: Function) { Object.seal(constructor);
          Object.seal(constructor.prototype); }
            在經(jīng)過TypeScript編譯后,將會生成一個__decorated()函數(shù),并應(yīng)用到Person類上,如下所示。
          var Person = /** @class */ (function() { function Person(name) { this.name =
          name; } Person= __decorate([sealed], Person); return Person; })();
            注意,類裝飾器不能出現(xiàn)在.d.ts聲明文件和外部類之中。

          二、方法裝飾器

            方法裝飾器聲明在類的方法之前,作用于方法的屬性描述符,比類裝飾器還多一個重載限制。它能接收三個參數(shù),如下所列:

           ?。?)對于靜態(tài)成員來說是類的構(gòu)造函數(shù),而對于實例成員則是類的原型對象。

            (2)成員的名字,一個字符串或符號。

           ?。?)成員的屬性描述符,當輸出版本低于ES5時,該值將會是undefined。


            當方法裝飾器返回一個值時,會覆蓋當前方法的屬性描述符。下面是一個簡單的例子,方法裝飾器的第一個參數(shù)是Person.prototype,第二個是“cover”,調(diào)用getName()方法得到的將是“freedom”,而不是原先的“strick”。
          class Person { @cover getName(name) { return name; } } function cover(target:
          any, key:string, descriptor: PropertyDescriptor) { descriptor.value =
          function() {return "freedom"; }; return descriptor; } let person = new
          Person(); person.getName("strick"); //"freedom"
          三、訪問器裝飾器


            訪問器裝飾器聲明在類的訪問器屬性之前,作用于相應(yīng)的屬性描述符,其限制與類裝飾器相同,而接收的三個參數(shù)與方法裝飾器相同。并且還需要注意一點,TypeScript不允許同時裝飾一個成員的get和set訪問器,只能應(yīng)用在第一個訪問器上。

            以下面的Person類為例,定義了一個訪問器屬性name,當訪問它時,得到的將是“freedom”,而不是原先的“strick”。
          class Person { private _name: string; @access get name() { return this._name; }
          set name(name) { this._name = name; } } function access(target: any, key: string
          , descriptor: PropertyDescriptor) { descriptor.get = function() { return "
          freedom"; }; return descriptor; } let person = new Person(); person.name = "
          strick"; console.log(person.name); //"freedom"
          四、屬性裝飾器


            屬性裝飾器聲明在屬性之前,其限制與訪問器裝飾器相同,但只能接收兩個參數(shù),不存在第三個屬性描述符參數(shù),并且沒有返回值。仍然以下面的Person類為例,定義一個name屬性,并且在@property裝飾器中修改其值。
          class Person { @property name: string; } function property(target: any, key:
          string) { Object.defineProperty(target, key, { value: "freedom" }); } let person
          =new Person(); person.name = "strick"; console.log(person.name); //"freedom"
          五、參數(shù)裝飾器


            參數(shù)裝飾器聲明在參數(shù)之前,它沒有返回值,其限制與方法裝飾器相同,并且也能接收三個參數(shù),但第三個參數(shù)表示裝飾的參數(shù)在函數(shù)的參數(shù)列表中所處的位置(即索引)。下面用一個例子來演示參數(shù)裝飾器的用法,需要與方法裝飾器配合。
          let params = []; class Person { @func getName(@required name) { return name; }
          }
            在@func中調(diào)用getName()方法,并向其傳入params數(shù)組中的值,@required用于修改指定位置的參數(shù)的值,如下所示。
          function func(target: any, key: string, descriptor: PropertyDescriptor) {
          const method= descriptor.value; descriptor.value = function () { return
          method.apply(this, params); }; return descriptor; } function required(target:
          any, key: string, index: number) { params[index]= "freedom"; }
            當實例化Person類,調(diào)用getName()方法,得到的將是“freedom”。
          let person = new Person(); person.getName("strick"); //"freedom"
          六、裝飾器工廠


            裝飾器工廠是一個能接收任意個參數(shù)的函數(shù),用來包裹裝飾器,使其更易使用,它能返回上述任意一種裝飾器函數(shù)。接下來改造方法裝飾器一節(jié)中的cover()函數(shù),接收一個字符串類型的value參數(shù),返回一個方法裝飾器函數(shù),如下所示。
          function cover(value: string) { return function(target: any, key: string,
          descriptor: PropertyDescriptor) { descriptor.value= function() { return value;
          };return descriptor; }; }
            在將@cover作用于類中的方法時,需要傳入一個字符串,如下所示。
          class Person { @cover("freedom") getName(name) { return name; } }
          七、裝飾器組合

            將多個裝飾器應(yīng)用到同一個聲明上時,既可以寫成一行,也可以寫成多行,如下所示。
          /****** 一行 ******/ @first @second desc /****** 多行 ******/ @first @second desc

            這些裝飾器的求值方式與復(fù)合函數(shù)類似,先由上至下依次執(zhí)行裝飾器,再將求值結(jié)果作為函數(shù),由下至上依次調(diào)用。例如定義兩個裝飾器工廠函數(shù),如下代碼所示,在函數(shù)體和返回的裝飾器中都會打印一個數(shù)字。
          function first() { console.log(1); return function(target: any, key: string,
          descriptor: PropertyDescriptor) { console.log(2); }; } function second() {
          console.log(3); return function(target: any, key: string, descriptor:
          PropertyDescriptor) { console.log(4); }; }
            將它們先后聲明到類中的同一個方法,如下代碼所示。根據(jù)求值順序可知,先打印出1和3,再打印出4和2。
          class Person { @first() @second() getName(name) { return name; } }
          ?

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                japonensis日本厨房乱 | 久热视频在线 | 六月婷婷啪啪 | 亚洲福利一区二区 | 久久99网站 |