最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Typescript協(xié)變與逆變簡單理解

 更新時間:2022年10月27日 16:41:55   作者:天地會珠海分舵  
深入學(xué)習(xí)TypeScript類型系統(tǒng)的話,逆變、協(xié)變、雙向協(xié)變、不變是繞不過去的概念。這些概念看起來挺高大上的,其實并不復(fù)雜,這篇文章我們就來學(xué)習(xí)下協(xié)變和逆變吧

1. 協(xié)變和逆變簡單理解

先簡單說下協(xié)變和逆變的理解。

首先,無論協(xié)變還是逆變,必然是存在于有繼承關(guān)系的類當(dāng)中,這個應(yīng)該好理解吧。如果你只有一個類,那沒有什么好變的。

其次,無論協(xié)變還是逆變,既然是變,那必然是存在不同類之間的對象的賦值,比如子類對象賦值給父類對象,父類對象賦值給子類對象,這樣才叫做變。

結(jié)合上面兩條,我覺得協(xié)變和逆變在我的字典中就能定義成:支持子類對象賦值給父類對象的情況稱之為協(xié)變;反之,支持父類對象賦值給子類對象的情況稱之為逆變。

舉個栗子,我們先假定我們有這么幾個類

class Animal {}
class Dog extends Animal {}
class Greyhound extends Dog {}

那么按照上面的理解,要整出一個示例的話,首先我們這里類的繼承關(guān)系這個條件有了,其次我們要整出的就是這幾個類賦值的情況,那么用實參和形參的方式來demo應(yīng)該是很不錯的選擇。

2. 協(xié)變舉例

那么協(xié)變的情況我們可以用代碼表示為

class Animal {}
class Dog extends Animal {
    bark(): void {
        console.log("Bark")
    }
}
class Greyhound extends Dog {}
function makeDogBark(dog:Dog) : void {
    dog.bark()
}
let dog: Dog = new Dog();
let greyhound: Greyhound = new Greyhound();
let animal: Animal = new Animal();
makeDogBark(greyhound) // OK。 子類賦值給父類
makeDogBark(animal) // Error。編譯器會報錯,父類不能賦值給子類

我們?nèi)绻忻嫦驅(qū)ο蠡A(chǔ)的話,相信對上面這段代碼不難理解, 子類賦值給父類,即協(xié)變的情況,在面向?qū)ο缶幊讨惺欠浅3R姷模疫@是實現(xiàn)語言多態(tài)特性的基礎(chǔ)。而多態(tài),卻又是實現(xiàn)眾多設(shè)計模式的基礎(chǔ)。

3. 逆變舉例

當(dāng)我們將函數(shù)作為參數(shù)進行傳遞時,就需要注意逆變的情況。比如下面的makeAnimalAction這個函數(shù),就嘗試錯誤的讓一只貓去做出狗吠的動作。

class Animal {
    doAnimalThing(): void {
        console.log("I am a Animal!")
    }
}
class Dog extends Animal {
    doDogThing(): void {
        console.log("I am a Dog!")
    }
}
class Cat extends Animal {
    doCatThing(): void {
        console.log("I am a Cat!")
    }
}
function makeAnimalAction(animalAction: (animal: Animal) => void) : void {
    let cat: Cat = new Cat()
    animalAction(cat)
}
function dogAction(dog: Dog) {
    dog.doDogThing()
}
makeAnimalAction(dogAction) // TS Error at compilation, since we are trying to use `doDogThing()` to a `Cat`

這里作為實參的dogAction函數(shù)接受一個Dog類型的參數(shù),而makeAnimalAction的形參animalAction接受一個Dog的父類Animal類型的參數(shù),返回值都是void,那么按照正常的思路,這時應(yīng)該可以像上面協(xié)變的例子一樣進行正常的賦值的。

但事實上編譯是不能通過的,因為最終makeAnimalAction中的代碼會嘗試以cat為參數(shù)去調(diào)用dogAction,然后讓一個cat去執(zhí)行doDogThing。

所以這里我們把函數(shù)作為參數(shù)傳遞時,如果該函數(shù)里面的參數(shù)牽涉到有繼承關(guān)系的類,就要特別注意下逆變情況的發(fā)生。

不過有vscode等代碼編輯工具的錯誤提示支持的話,應(yīng)該也很容易排除這種錯誤。

4. 更簡單點的理解

我覺得將上面的例子稍微改動下,將makeAnimalAction的形參的類型抽出來定義成一個type,應(yīng)該會有助于我們理解上面的代碼。

class Animal {
    doAnimalThing(): void {
        console.log("I am a Animal!")
    }
}
class Dog extends Animal {
    doDogThing(): void {
        console.log("I am a Dog!")
    }
}
class Cat extends Animal {
    doCatThing(): void {
        console.log("I am a Cat!")
    }
}
function makeAnimalAction(animalAction: AnimalAction) : void {
    let cat: Cat = new Cat()
    animalAction(cat)
}
type AnimalAction =  (animal: Animal) => void
type DogAction =  (dog: Dog) => void
let dogAction: DogAction = (dog: Dog) => {
    dog.doDogThing()
}
const animalAction: AnimalAction = dogAction // Error: 和上面一樣的逆變導(dǎo)致的錯誤
makeAnimalAction(animalAction)
  • animalAction(animal: Animal)函數(shù),我們可以將其理解成一個可以讓動物做動物都有的動作的函數(shù)。因此我們可以傳dog、cat或者animal進去作為參數(shù),因為它們都是動物,然后animalAction內(nèi)部可以調(diào)用animal.doAnimalThing方法,但不能調(diào)用doCatThing或者doDogThing這些方法,因為這些不是所有動物共有的方法。
  • dogAction(dog: Dog)函數(shù), 同上,我們可以將其理解成一個可以讓狗狗做狗狗都有的動作的函數(shù)。因此可傳dog,greyHound這些狗狗對象作為參數(shù),因為對他們都是狗狗,然后dogAction內(nèi)部可以調(diào)用dog.doDogThing和dog.doAnimalThing, 因為這些都是狗狗共有的動作。但是不能調(diào)用dog.doGrenHoundThing,因為這不是狗狗共有的動作,只有狗狗的子類灰狗用歐這樣的函數(shù)。

以上兩個都是協(xié)變的情況。下面我們看下逆變所導(dǎo)致的錯誤那一行。

animalAction = dogAction,如果有C/C++經(jīng)驗的,就可以理解成一個函數(shù)指,指向另外一個函數(shù),否則理解成一個函數(shù)復(fù)制給另外一個函數(shù)也可以。

假如這個語句可以執(zhí)行,那么執(zhí)行之前,dogAction(dog: Dog)只能接受Dog和GreyHound類型的對象,然后去做狗狗都有的動作。

執(zhí)行之后,因為現(xiàn)在animalAction指向了dogAction,但是animalAction自身的參數(shù)是(animal: Animal),即可以接受所有動物類型的對象。

所以最終這里animalAction就變成了這幅模樣(隱隱約約覺得這是理解的關(guān)鍵):

function animalAction(animal: Animal) {
 animal.doDogThing()
}

這很明顯就是不合理的嘛!所有狗狗都是動物,但這里反過來就不行,不是所有動物都能做狗狗能做的事情,比如這里傳個Cat對象進來,那豈不就是讓貓去做狗狗的事情了嗎。

而反過來,這里假如我們先定義了animalAction, 然后我們讓dogAction = animalAction,這種做法卻是可行的。我們看最終dogAction變成

function dogAction(dog: Dog) {
 dog.doAnimalThing()
}

即dogAction(dog:Dog)指向了animalAction(animal: Animal), 也就是一個以父類型的對象為參數(shù)的函數(shù)賦予給了一個以子類型的對象為參數(shù)的函數(shù),這和我們協(xié)變時候的對象之間的賦值時,只能子對象賦值給父對象的做法是相反的。我想,這應(yīng)該也是為什么叫做逆變的原因吧。

本來這里在我頭腦過的時候感覺應(yīng)該很容易說清楚的,沒有想到寫下來的時候還是得寫這么一大堆,希望能有幫助吧。

5. 參考

https://dev.to/codeozz/how-i-understand-covariance-contravariance-in-typescript-2766

到此這篇關(guān)于Typescript協(xié)變與逆變簡單理解的文章就介紹到這了,更多相關(guān)Typescript協(xié)變與逆變內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • WebGL?多重紋理的使用介紹

    WebGL?多重紋理的使用介紹

    這篇文章主要為大家介紹了WebGL 多重紋理的使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • JS小知識之如何將CSV轉(zhuǎn)換為JSON字符串

    JS小知識之如何將CSV轉(zhuǎn)換為JSON字符串

    CSV文件一般是以逗號為分隔值的文件(Comma-Separated?Values,CSV,有時也稱為字符分隔值,因為分隔字符也可以不是逗號),其文件以純文本形式存儲表格數(shù)據(jù)(數(shù)字和文本),下面這篇文章主要給大家介紹了JS小知識之如何將CSV轉(zhuǎn)換為JSON字符串的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • 通過說明與示例了解js五種設(shè)計模式

    通過說明與示例了解js五種設(shè)計模式

    這篇文章主要介紹了通過說明與示例了解js五種設(shè)計模式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,,需要的朋友可以參考下
    2019-06-06
  • javascript字符串替換及字符串分割示例代碼

    javascript字符串替換及字符串分割示例代碼

    javascript中的字符串替換及字符串分割在某些情況下還是比較實用的,下面有個不錯的示例,感興趣的朋友可以參考下
    2013-12-12
  • JavaScript中的錯誤處理全面指南

    JavaScript中的錯誤處理全面指南

    在JavaScript開發(fā)中,錯誤處理是一個不可忽視的重要環(huán)節(jié),本文將深入探討JavaScript中的錯誤處理機制,包括錯誤的類型、捕獲與拋出錯誤的方法,需要的可以參考下
    2024-10-10
  • 一些很實用且必用的小腳本代碼

    一些很實用且必用的小腳本代碼

    一些很實用且必用的小腳本代碼...
    2006-08-08
  • js+Html實現(xiàn)表格可編輯操作

    js+Html實現(xiàn)表格可編輯操作

    這篇文章主要為大家詳細(xì)介紹了js+Html實現(xiàn)表格可編輯操作,能動態(tài)添加刪除行,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • 詳解JavaScript如何實現(xiàn)異步并發(fā)任務(wù)控制器

    詳解JavaScript如何實現(xiàn)異步并發(fā)任務(wù)控制器

    實現(xiàn)一個控制并發(fā)數(shù)的任務(wù)隊列?、實現(xiàn)一個異步并發(fā)任務(wù)控制器,這已經(jīng)是非常經(jīng)典的手寫題目了,因為其中涉及?異步?和?并發(fā)?的內(nèi)容,所以本文就來講講到底如何實現(xiàn)呢
    2023-05-05
  • 微信企業(yè)號開發(fā)之微信考勤百度地圖定位

    微信企業(yè)號開發(fā)之微信考勤百度地圖定位

    本文給大家介紹微信企業(yè)號開發(fā)之微信考勤百度地圖定位,有需要的朋友參考下本篇文章
    2015-09-09
  • JS實現(xiàn)圖片高斯模糊切換效果的焦點圖實例

    JS實現(xiàn)圖片高斯模糊切換效果的焦點圖實例

    這篇文章主要給大家介紹了利用原生JS如何實現(xiàn)圖片高斯模糊切換效果的焦點圖,文中給出了完整的實例代碼,相信對大家的理解和學(xué)習(xí)具有一定的參考借鑒價值,下面來一起看看吧。
    2017-01-01

最新評論

谢通门县| 将乐县| 洪洞县| 静乐县| 化德县| 遂宁市| 顺义区| 钟山县| 华阴市| 云阳县| 漠河县| 黔西县| 遂昌县| 湖南省| 南华县| 岫岩| 西乌珠穆沁旗| 永胜县| 且末县| 且末县| 焦作市| 广州市| 湘乡市| 苍溪县| 米脂县| 阜新| 吉首市| 界首市| 海盐县| 塘沽区| 垦利县| 家居| 米泉市| 永泰县| 洛浦县| 六盘水市| 道孚县| 定陶县| 临汾市| 崇仁县| 原平市|