這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一.typescript 高階類型 Exclude 和 Extract Exclude<T, U> TypeScript 2.8 中增加了 Exclude 類型,該如何理解這個高級類型的定義呢? type Exclude<T, U> = ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
一.typescript 高階類型 Exclude 和 Extract
Exclude<T, U>
TypeScript 2.8
中增加了 Exclude
類型,該如何理解這個高級類型的定義呢?
type Exclude<T, U> = T extends U ? never : T;
從 Exclude
的定義來看,就是判斷 T
是否繼承於 U
,如果是,則返回 never
,否則返回 T
。
1. T, U 之間的關係,是否是基於結構相似呢?
interface IPerson { name: string, age: number, sex: 0 | 1, } interface IMan { name: string, age: number, } type Man = Exclude<IPerson, IMan> // 等效於 type Man = never
結論:只需要兩者類型能夠保持一致,同時 T
的類型能夠相容 U
的類型即可。
2. 對於聯合類型,是如何進行類比的?
type Fruits = "apple" | "banana" | 'peach' | 'orange'; type DislikeFruits = "apple" | "banana"; type FloveFruits = Exclude<Fruits, DislikeFruits> // 等效於 type FloveFruits = "peach" | "orange" // 實際上 Exclude 進行的比較 type FloveFruits = | ("apple" extends "apple" | "banana" ? never : "apple") | ("banana" extends "apple" | "banana" ? never : "banana") | ("peach" extends "apple" | "banana" ? never : "peach") | ("orange" extends "apple" | "banana" ? never : "orange") // 所以最後的結果 type FloveFruits = "peach" | "orange"
當入參是聯合類型時,它會以分散式的形式去進行比較。
Extract<T, U>
Extract
的功能,與 Exclude
相反,它是 提取 T
中可以賦值給 U
的類型。
type Extract<T, U> = T extends U ? T : never
1. T, U 之間的關係,是否是基於結構相似呢?
interface IPerson { name: string, age: number, sex: 0 | 1, } interface IMan { name: string, age: number, } type Man = Extract<IPerson, IMan> // 等效於 type Man = IPerson
與 Exclude
相同,均是保持相同的結構即可,只不過他們的取值邏輯相反。
2. 對於聯合類型,是如何進行類比的?
type Fruits = "apple" | "banana" | 'peach' | 'orange'; type DislikeFruits = "apple" | "banana"; type FloveFruits = Extract<Fruits, DislikeFruits> // 等效於 type FloveFruits = "apple" | "banana"
原理與 Exclude
類似,僅僅是取值的邏輯不同而已。
二.vue事件方法之$off方法的實現原理
vue中事件方法一共就四個,掛載在vue實例上的$off移除事件中心裡面某個事件的回調函數,通常會用到,那麼$off的內部實現原理是什麼呢?下麵我們來詳細說下$off:
vm.$off( [event, callback] )
參數:
{string | Array<string>} event (只在 2.2.2+ 支持數組) {Function} [callback]
作用:
移除自定義事件監聽器。
如果沒有提供參數,則移除所有的事件監聽器;
如果只提供了事件,則移除該事件所有的監聽器;
如果同時提供了事件與回調,則只移除這個回調的監聽器。
原理:
該方法用來移除事件中心裡面某個事件的回調函數,根據所傳入參數的不同,作出不同的處理。
Vue.prototype.$off = function (event, fn) { const vm: Component = this // all if (!arguments.length) { vm._events = Object.create(null) return vm } // array of events if (Array.isArray(event)) { for (let i = 0, l = event.length; i < l; i++) { this.$off(event[i], fn) } return vm } // specific event const cbs = vm._events[event] if (!cbs) { return vm } if (!fn) { vm._events[event] = null return vm } if (fn) { // specific handler let cb let i = cbs.length while (i--) { cb = cbs[i] if (cb === fn || cb.fn === fn) { cbs.splice(i, 1) break } } } return vm }
該方法內部就是通過不斷判斷所傳參數的情況進而進行不同的邏輯處理。
首先,判斷如果沒有傳入任何參數(即arguments.length
為0),這就是第一種情況:如果沒有提供參數,則移除所有的事件監聽器。我們知道,當前實例上的所有事件都存儲在事件中心_events
屬性中,要想移除所有的事件,那麼只需把_events
屬性重新置為空對象即可。
接著,判斷如果傳入的需要移除的事件名是一個數組,就表示需要一次性移除多個事件,那麼我們只需同訂閱多個事件一樣,遍歷該數組,然後將數組中的每一個事件都遞歸調用$off方法進行移除即可。
接著,獲取到需要移除的事件名在事件中心中對應的回調函數cbs。
接著,判斷如果cbs不存在,那表明在事件中心從來沒有訂閱過該事件,那就談不上移除該事件,直接返回,退出程式即可。
接著,如果cbs存在,但是沒有傳入回調函數fn,這就是第二種情況:如果只提供了事件,則移除該事件所有的監聽器。這個也不難,我們知道,在事件中心裡面,一個事件名對應的回調函數是一個數組,要想移除所有的回調函數我們只需把它對應的數組設置為null即可。
接著,如果既傳入了事件名,又傳入了回調函數,cbs也存在,那這就是第三種情況:如果同時提供了事件與回調,則只移除這個回調的監聽器。那麼我們只需遍歷所有回調函數數組cbs,如果cbs中某一項與fn相同,或者某一項的fn屬性與fn相同,那麼就將其從數組中刪除即可。
就這麼簡單。