日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅入浅出Typescript Decorators

發布時間:2023/12/31 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅入浅出Typescript Decorators 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

臨時起的興趣,想寫一篇關于ts decorator的文章,就花小半天整理了一下...
這東西,在ES2017里好像也有... 文檔的話看這里。
因為臨時,也沒想寫太多文字介紹,帶少許文字說明直接開擼代碼吧。

本文通過ts編譯后的decorator代碼解釋一番裝飾器是什么?能做什么?有什么好處?

實現代碼

編譯后代碼是這樣的,帶注釋:

var __decorate =(this && this.__decorate) ||function(decorators, target, key, desc) {// c 參數長度// r ? c < 3 則是target,否則先判斷desc為null的話則將desc取target的key屬性的描述,再否則便是desc了// d 預留使用var c = arguments.length,r =c < 3? target: desc === null? (desc = Object.getOwnPropertyDescriptor(target, key)): desc,d;// 下面文字解釋,這僅是個甩鍋的行為if (typeof Reflect === "object" && typeof Reflect.decorate === "function")r = Reflect.decorate(decorators, target, key, desc);// 循環 decorators 并每次賦值給 d,并且判斷值elsefor (var i = decorators.length - 1; i >= 0; i--)if ((d = decorators[i]))// c < 3 ,用 r 作為 decorators[i] 的入參執行;// c > 3 ,target, key, r 作為 decorators[i] 的入參執行;// c === 3,target, key 作為 decorators[i] 的入參執行。// 如果執行無返回結果, r = r;。r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;// 如果 c > 3 && r , 修改 target ,返回 rreturn c > 3 && r && Object.defineProperty(target, key, r), r;};

從代碼里可以看出,最終結果要么是用decorator執行target,從而改變一些什么東西;要么就是使用Object.defineProperty來對target來做操作,代碼就幾行,用處確不小...具體的執行過程結合下面的兩個例子會更容易理解。

值得一提的是,關于代碼里的Reflect原本以為是這個 sec-reflect-object 里的方法,但可惜不是;

然后猜測是Typescript的實現,翻了Typescript/tsc.js的代碼(如果打不開鏈接就從 node_modules 下看吧),發現也不是,再去查 stackoverflow 的解釋,是這樣的 what-is-reflect-decorate-in-js-code-transpiled-from-ts

大致說是ts希望把這個鍋甩給ES來補,到時候ts的else里的代碼便是polyfill了

案例

以下面的 decorator 和 class 作為例子解釋

// ts 代碼 function show(target: any) {console.log(target);target.prototype.showMe = (name: string) => {console.log("show me :", name);}; }interface IShow {showMe?(name: string): any; }@show class Show implements IShow {showMe(name: string) {} }const shoow = new Show(); shoow.showMe("ys");// 編譯后的js // decorator ,簡單的打印,并且修改方法 function show(target) {console.log(target);target.prototype.showMe = function(name) {console.log("show me :", name);}; }// class Shoow var Shoow = (function() {function Shoow() {}Shoow.prototype.showMe = function(name) {};// decorators 為[show],target 為 ShoowShoow = __decorate([show], Shoow);return Shoow; })();var shooow = new Shoow(); shooow.showMe("ys");// output : show me : ys

理解一下執行步驟:

  • decorators = [show],target = Shoow,
  • c = 2,r = target{Shoow},d = undefined
  • 不存在 Reflect,走循環,只循環一次
  • d = show,r = show(target{Shoow}),r 沒返回結果,所以 r 還是 r , r = target{Shoow}
  • return 結果: c = 2, 所以返回 false
  • 執行后無返回值,但是在執行show(target{Shoow})的時候將showMe方法改掉了,于是執行結果符合預期
  • 一個不夠?再來一個?這次在里面返回一個函數試試?

    // ts代碼 function logger1(config?) {return function(target, key: string, descriptor: PropertyDescriptor) {const _value = descriptor.value;if (typeof _value === "function") {descriptor.value = (...args) => {console.log(`logger1-begin : ${config.level}`);const res = _value.apply(target, args);console.log(`logger1-end`);return res;};}return descriptor;}; }function logger2(config?) {return function(target, key: string, descriptor: PropertyDescriptor) {const _value = descriptor.value;if (typeof _value === "function") {descriptor.value = (...args) => {console.log(`logger2-begin : ${config.level}`);const res = _value.apply(target, args);console.log(`logger2-end`);return res;};}return descriptor;}; }interface IShow {showMe?(name: string): any; }class Show implements IShow {@logger1({ level: "info" })@logger2({ level: "error" })showMe(name: string) {console.log("show me :", name);} }const shoow = new Show(); shoow.showMe("ys");// output 這里手動加個縮進,這時候showMe方法已經經過多次包裹 // logger1-begin : info // logger2-begin : error // show me : ys // logger2-end // logger1-end

    再來看看執行步驟:

  • decorators = [logger1, logger2],target = Shoow,key = "showMe",desc = null 注意,這里是為null,不是為undefined
  • c = 4,r = target{Shoow},d = undefined
  • 不存在 Reflect,走循環,只循環一次
  • 第一次循環取 d = logger1,r = logger1(target, key, r),因為 return 存在值,r = logger1 的返回函數,這時候 descriptor.value 被第一次重寫
  • 第二次循環取 d = logger2,r = logger2(target, key, r),又因為 return 存在值,r = logger2 的返回函數,這時候 descriptor.value 被第二次重寫
  • return 結果: 因為 c > 3,r 存在值,執行 Object.defineProperty(target, key, r)來重寫對象屬性并且返回 r (r為重寫的結果)
  • 經過 2 次重寫 showMe 屬性值,執行結果符合預期
  • 歡樂

    裝飾器給你帶來什么歡樂?簡單列幾個最明顯的優點,其他在運用中各自提取每日份的快樂去吧...

  • 業務和功能之間的解耦(比如日志)
  • // 日常dosomething(){consol.log('start')// some thingconsole.log('end')}// 使用裝飾器@logger(logConfig?)dosomething();
  • 代碼結構清晰(特別針對多層HOC后的React組件)
  • // 日常多層HOCclass MyComponent extends Component{// ..}connect(mapFn)(MyHoc(someMapFn)(Form.create(fieldsMapFn)(MyComponent)))// 使用裝飾器@connect(mapFn)@MyHoc(someMapFn)@FormFields(fieldsMapFn)class MyComponent extends Component{// ..}export default MyComponent;

    最后

    AOP,了解一下

    總結

    以上是生活随笔為你收集整理的浅入浅出Typescript Decorators的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。