欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談JS裝飾器以及裝飾器在TS中的使用方式

 更新時(shí)間:2023年07月16日 09:30:01   作者:菜雞夯師傅  
這篇文章主要帶大家探討一下JS裝飾器以及裝飾器在TS中的使用方式,文中有詳細(xì)的代碼示例,對(duì)裝飾器不太了解的同學(xué)可以參考閱讀本文學(xué)習(xí)了一下

類裝飾器

什么是類裝飾器呢?

類裝飾器的本質(zhì)是一個(gè)函數(shù),該函數(shù)接受一個(gè)參數(shù),表示類本身(構(gòu)造函數(shù)本身)。 那么類裝飾器該如何使用呢?

    function decorator (target) {
    }
    @decorator
    class A {
    }

這樣的話就完成了類裝飾器的編寫。不難看出類裝飾器的調(diào)用方式就是@函數(shù)名的方式放在一個(gè)類的聲明之前。那如果在TS中使用的話,我們都知道TS中有類型檢查,那對(duì)于裝飾器而言,主要在形參的類型上需要我們自己定義。那類裝飾器的形參表示的是類本身,該如何定義呢?

我們知道JS中的類其實(shí)就是一個(gè)函數(shù),所以我們可以使用Function來(lái)對(duì)類進(jìn)行類型定義。但是這不是很嚴(yán)謹(jǐn),因?yàn)轭愂强梢杂?code>new關(guān)鍵字來(lái)聲明的,并且會(huì)返回一個(gè)object,所以更推薦使用new (參數(shù)) => object來(lái)定義類的類型。那么以上代碼就會(huì)被改造成這樣:

    type decoratorType = new (...args:any[]) => object;
    function decorator ( target : decorarorType ) {
    };
    @decorator;
    class A {
    }

值得注意的是,ts可能會(huì)在類名處有錯(cuò)誤提示,這是因?yàn)檠b飾器在ts中還處于試驗(yàn)階段。我們可以在 tsconfig.json中配置experimentalDecoratorstrue來(lái)規(guī)避這個(gè)報(bào)錯(cuò)。

類裝飾器的運(yùn)行時(shí)機(jī)

類裝飾器的運(yùn)行時(shí)間是在類定義后直接運(yùn)行。我們可以驗(yàn)證一下:

運(yùn)行后發(fā)現(xiàn),在class A定義完成后立即就輸出了我是decorator。

從編譯結(jié)果上也能很容易的看出,裝飾器是在類定義后直接調(diào)用的:

  // 這里有一個(gè)函數(shù) 他的第一個(gè)參數(shù)decorators表示裝飾器數(shù)組,第二個(gè)參數(shù)target表示被裝飾的類本身。
  var __decorate =
  (this && this.__decorate) ||
  function (decorators, target, key, desc) {
    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")
     // 調(diào)用裝飾器
      r = Reflect.decorate(decorators, target, key, desc);
    else
      for (var i = decorators.length - 1; i >= 0; i--)
       // 調(diào)用裝飾器(從后往前)
        if ((d = decorators[i]))
          r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
  };
// 這時(shí)我們定義的裝飾器函數(shù)
function decotator(target) {
  console.log("我是decorator");
}
// 定義類
let A = class A {};
// 裝飾器和類作為參數(shù)傳入__decorate中運(yùn)行。
A = __decorate([decotator], A);

裝飾器的返回值

裝飾器可以有以下幾種返回值:

  • void
  • 一個(gè)新的類:會(huì)將新的類替換掉裝飾目標(biāo)

這里具體演示第二種返回值----返回一個(gè)新的類。在裝飾器中返回新的類class B。此時(shí)new一個(gè)class A的實(shí)例,打印后發(fā)現(xiàn)為class B的實(shí)例對(duì)象。說(shuō)明class A通過裝飾器已經(jīng)被替換為class B了。

所以說(shuō)在裝飾器中可以通過以上方式,增強(qiáng)被裝飾類的功能。不過在ts中這種方式可能丟失一些類型檢查。如下圖:

這是因?yàn)檠b飾器是一個(gè)通用的,雖然在當(dāng)前場(chǎng)景下因?yàn)?code>class B繼承了裝飾器傳入的class A,因?yàn)轭愌b飾器的入?yún)⑹?strong>動(dòng)態(tài)的,所以ts并不能知道到底有沒有prop1這個(gè)屬性。當(dāng)然這樣并不會(huì)影響代碼的功能,只是在ts中會(huì)丟失類型檢查。

那么如果我想讓裝飾器能夠接受一些額外的內(nèi)容,該怎么做呢?在實(shí)際開發(fā)中,可能需要某些數(shù)據(jù)來(lái)參與邏輯。那么我們可以用以下方式來(lái)實(shí)現(xiàn):

type decoratorType = new (...args: any) => object;
function decorator(str: string) {
  return function (target: decoratorType) {
    console.log(str);
    console.log(target);
  };
}
@decorator("這是一個(gè)類")
class A {}

因?yàn)樾枰邮茴~外的信息,所以這必然是需要一個(gè)函數(shù)調(diào)用的形式。這里 @decorator接受了一個(gè)字符串參數(shù)。并且decorator函數(shù)接受一個(gè)形參str且返回一個(gè)新的函數(shù),所以decorator函數(shù)返回的函數(shù)會(huì)作為真正的裝飾器,它可以接收到被修飾類class A。我們可以看一下運(yùn)行結(jié)果。

多個(gè)裝飾器的情況

那么如果有多個(gè)裝飾器呢?他們的運(yùn)行順序是我們想的那樣從上到下依次運(yùn)行的嗎?比如有以下代碼:

type decoratorType = new (...args: any) => object;
function decorator1(target: decoratorType) {
  console.log("我是裝飾器1");
}
function decorator2(target: decoratorType) {
  console.log("我是裝飾器2");
}
function decorator3(target: decoratorType) {
  console.log("我是裝飾器3");
}
@decorator1
@decorator2
@decorator3
class A {}

按照我們一貫的思維,因?yàn)槭峭酱a,所以會(huì)按順序執(zhí)行,事實(shí)真的是這樣嗎?讓我們來(lái)看一下運(yùn)行結(jié)果:

不難發(fā)現(xiàn)裝飾器的運(yùn)行順序是遵循后加入先調(diào)用的形式!從編譯結(jié)果也能發(fā)現(xiàn):

var __decorate =
  (this && this.__decorate) ||
  function (decorators, target, key, desc) {
    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")
     // 調(diào)用裝飾器
      r = Reflect.decorate(decorators, target, key, desc);
    else
      for (var i = decorators.length - 1; i >= 0; i--)
       //看這里 調(diào)用裝飾器(從后往前因?yàn)槭莍--且i的初始值是裝飾器數(shù)組的實(shí)際長(zhǎng)度)
        if ((d = decorators[i]))
          r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
  };

那如果把裝飾器作為一個(gè)函數(shù)來(lái)調(diào)用呢?

type decoratorType = new (...args: any) => object;
function decorator1(str: string) {
  console.log("第一個(gè)函數(shù)運(yùn)行了");
  return function (target: decoratorType) {
    console.log(str);
  };
}
function decorator2(str: string) {
  console.log("第二個(gè)函數(shù)運(yùn)行了");
  return function (target: decoratorType) {
    console.log(str);
  };
}
function decorator3(str: string) {
  console.log("第三個(gè)函數(shù)運(yùn)行了");
  return function (target: decoratorType) {
    console.log(str);
  };
}
@decorator1("我是裝飾器1")
@decorator2("我是裝飾器2")
@decorator3("我是裝飾器3")
class A {}

當(dāng)作為函數(shù)調(diào)用時(shí),會(huì)先執(zhí)行函數(shù)體,因?yàn)樵摵瘮?shù)又返回了一個(gè)函數(shù),所以返回的新函數(shù)會(huì)作為裝飾器。運(yùn)行第一個(gè)函數(shù)會(huì)的到第一個(gè)裝飾器,以此類推會(huì)獲得三個(gè)裝飾器。而裝飾器是按照后加入先調(diào)用的形式,所以會(huì)輸出以下結(jié)果:

從編譯結(jié)果來(lái)看能更好的理解:

function decorator1(str) {
  console.log("第一個(gè)函數(shù)運(yùn)行了");
  return function (target) {
    console.log(str);
  };
}
function decorator2(str) {
  console.log("第二個(gè)函數(shù)運(yùn)行了");
  return function (target) {
    console.log(str);
  };
}
function decorator3(str) {
  console.log("第三個(gè)函數(shù)運(yùn)行了");
  return function (target) {
    console.log(str);
  };
}
let A = class A {};
A = __decorate(
  [
    decorator1("我是裝飾器1"), // 第一個(gè)函數(shù)的返回結(jié)果作為裝飾器
    decorator2("我是裝飾器2"), // 第二個(gè)函數(shù)的返回結(jié)果作為裝飾器
    decorator3("我是裝飾器3"), // 第三個(gè)函數(shù)的返回結(jié)果作為裝飾器
  ],
  A
);

結(jié)尾

如果讀完這篇文章能夠幫助你更好的理解類裝飾器,歡迎留言討論、點(diǎn)贊收藏。

以上就是淺談JS裝飾器以及裝飾器在TS中的使用方式的詳細(xì)內(nèi)容,更多關(guān)于JS裝飾器使用方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS獲取時(shí)間的相關(guān)函數(shù)及時(shí)間戳與時(shí)間日期之間的轉(zhuǎn)換

    JS獲取時(shí)間的相關(guān)函數(shù)及時(shí)間戳與時(shí)間日期之間的轉(zhuǎn)換

    時(shí)間戳和時(shí)間日期的轉(zhuǎn)換是常見的操作,下面就通過代碼實(shí)例介紹一下如何實(shí)現(xiàn)它們之間的相互轉(zhuǎn)換,感興趣的朋友一起學(xué)習(xí)吧
    2016-02-02
  • JavaScript實(shí)現(xiàn)計(jì)數(shù)器基礎(chǔ)方法

    JavaScript實(shí)現(xiàn)計(jì)數(shù)器基礎(chǔ)方法

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)計(jì)數(shù)器的基礎(chǔ)方法
    ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • javascript 處理事件綁定的一些兼容寫法

    javascript 處理事件綁定的一些兼容寫法

    javascript 事件綁定的一些兼容寫法整理非常不錯(cuò),感謝
    2009-12-12
  • js圖片輪播特效代碼分享

    js圖片輪播特效代碼分享

    這篇文章主要介紹了js圖片輪播特效,圖片切換效果特別適合做產(chǎn)品演示,感興趣的小伙伴可以參考下
    2015-09-09
  • JS實(shí)現(xiàn)代碼雨特效

    JS實(shí)現(xiàn)代碼雨特效

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)代碼雨特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • JavaScript中的字符串操作詳解

    JavaScript中的字符串操作詳解

    這篇文章介紹了JavaScript中的字符串操作,有需要的朋友可以參考一下
    2013-11-11
  • javascript導(dǎo)出csv文件(excel)的方法示例

    javascript導(dǎo)出csv文件(excel)的方法示例

    這篇文章主要給大家介紹了關(guān)于javascript導(dǎo)出csv文件(excel)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用javascript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 詳解js location.href和window.open的幾種用法和區(qū)別

    詳解js location.href和window.open的幾種用法和區(qū)別

    這篇文章主要介紹了詳解js location.href和window.open的幾種用法和區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • bootstrap手風(fēng)琴制作方法詳解

    bootstrap手風(fēng)琴制作方法詳解

    這篇文章主要為大家詳細(xì)介紹了bootstrap手風(fēng)琴的制作方法,制作聲明式觸發(fā)手風(fēng)琴,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 前端常用的js函數(shù)方法

    前端常用的js函數(shù)方法

    這篇文章主要給大家分享的是常用的js函數(shù)的方法,告別搜索引擎的幫助,提高你的開發(fā)效率,,需要的朋友可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助
    2021-12-12

最新評(píng)論