vscode工具函數(shù)once使用示例深入剖析
背景
once
函數(shù)的起源可以追溯到函數(shù)式編程。在函數(shù)式編程中,函數(shù)被視為不可變的,這意味著它們不應(yīng)修改任何狀態(tài)或引用任何狀態(tài)。因此,在函數(shù)式編程中,通常需要一些技巧來(lái)處理一些常見問(wèn)題,例如避免在多次調(diào)用相同函數(shù)時(shí)進(jìn)行冗余計(jì)算。
once
函數(shù)是解決此問(wèn)題的一種方法。它可以將函數(shù)轉(zhuǎn)換為只能調(diào)用一次的函數(shù),并使用一些技巧來(lái)避免冗余計(jì)算。使用 once
函數(shù)可以減少計(jì)算時(shí)間和資源的消耗,并提高應(yīng)用程序的性能。
once
函數(shù)在現(xiàn)代 JavaScript 庫(kù)和框架中非常常見,例如 lodash
。它們提供了許多內(nèi)置的 once
函數(shù)來(lái)處理各種場(chǎng)景和問(wèn)題。在實(shí)際開發(fā)中,我們可以使用這些函數(shù)來(lái)提高代碼的可維護(hù)性和可讀性,避免冗余計(jì)算和網(wǎng)絡(luò)請(qǐng)求,并提高應(yīng)用程序的性能。
VSCode中的實(shí)現(xiàn)
export function once<T extends Function>(this: unknown, fn: T): T { const _this = this; let didCall = false; let result: unknown; return function () { if (didCall) { return result; } didCall = true; result = fn.apply(_this, arguments); return result; } as unknown as T; }
這個(gè)實(shí)現(xiàn)比較簡(jiǎn)單,但還是詳細(xì)分析解釋一下代碼
- 函數(shù)簽名:
once<T extends Function>(this: unknown, fn: T): T
。該函數(shù)使用了泛型參數(shù)**T
,表示被封裝的原始函數(shù)的類型。它還定義了一個(gè)this
參數(shù),表示封裝函數(shù)中的this
關(guān)鍵字的類型為unknown
,以及一個(gè)fn
**參數(shù),表示被封裝的原始函數(shù)。 - 緩存結(jié)果:在函數(shù)內(nèi)部,定義了三個(gè)變量。**
_this
變量引用了函數(shù)中的this
關(guān)鍵字,并將其保存在變量中。didCall
變量用于跟蹤函數(shù)是否已經(jīng)被調(diào)用過(guò)。result
**變量用于保存函數(shù)的結(jié)果。 - 返回新函數(shù):函數(shù)內(nèi)部返回了一個(gè)匿名函數(shù),它接受任意數(shù)量的參數(shù),并將其傳遞給原始函數(shù)。在函數(shù)內(nèi)部,首先檢查函數(shù)是否已經(jīng)被調(diào)用過(guò)。如果是,則直接返回之前保存的結(jié)果。否則,將**
didCall
**標(biāo)記為已調(diào)用,并調(diào)用原始函數(shù)并保存結(jié)果。最后,返回結(jié)果。 - 類型斷言:函數(shù)的返回值是一個(gè)匿名函數(shù),但是它的類型需要與原始函數(shù)相同。因此,使用了一個(gè)類型斷言將匿名函數(shù)的類型強(qiáng)制轉(zhuǎn)換為泛型參數(shù)**
T
**。
lodash的實(shí)現(xiàn)
lodash
到目前的版本已經(jīng)是高度封裝了,它的源碼可以在**github.com/lodash/loda…**看到:
function once(func) { return before(2, func) }
它本身是調(diào)用了 before
函數(shù), before
是一個(gè)經(jīng)過(guò)高度抽象的函數(shù),它在被調(diào)用次數(shù)達(dá)到指定次數(shù)之前,會(huì)繼續(xù)執(zhí)行傳入的函數(shù),而在達(dá)到指定次數(shù)時(shí),會(huì)返回最后一次執(zhí)行傳入函數(shù)的結(jié)果:
function before(n, func) { let result if (typeof func !== 'function') { throw new TypeError('Expected a function') } return function(...args) { if (--n > 0) { result = func.apply(this, args) } if (n <= 1) { func = undefined } return result } }
對(duì)于 lodash
這樣的工具庫(kù)而言,它的抽象層次要比 vscode
更高,但實(shí)現(xiàn)的原理是相同的,核心都是利用閉包,通過(guò)內(nèi)部變量的狀態(tài)來(lái)判斷函數(shù)是否已經(jīng)被調(diào)用過(guò),從而保證原始函數(shù)只被執(zhí)行一次。
once的應(yīng)用
**once
**函數(shù)是一個(gè)常見的JavaScript函數(shù),它用于確保一個(gè)函數(shù)只能被調(diào)用一次。這個(gè)函數(shù)在以下幾個(gè)場(chǎng)景下非常有用:
- 緩存函數(shù)的結(jié)果:當(dāng)一個(gè)函數(shù)需要執(zhí)行復(fù)雜的計(jì)算時(shí),我們可以使用**
once
**函數(shù)來(lái)確保它只會(huì)被調(diào)用一次,并將結(jié)果緩存下來(lái)。在之后的調(diào)用中,函數(shù)會(huì)直接返回緩存的結(jié)果,而不會(huì)再次執(zhí)行計(jì)算。這可以節(jié)省計(jì)算時(shí)間和資源,并提高應(yīng)用程序的性能。 - 避免重復(fù)網(wǎng)絡(luò)請(qǐng)求:當(dāng)我們需要向服務(wù)器發(fā)送請(qǐng)求時(shí),可以使用**
once
**函數(shù)來(lái)確保只發(fā)送一次請(qǐng)求,并在之后的調(diào)用中直接返回結(jié)果。這可以避免發(fā)送重復(fù)的網(wǎng)絡(luò)請(qǐng)求,并提高應(yīng)用程序的響應(yīng)速度。 - 確保只運(yùn)行一次的初始化代碼:有時(shí)候我們需要在應(yīng)用程序啟動(dòng)時(shí)執(zhí)行一些初始化代碼,例如創(chuàng)建全局變量或注冊(cè)事件處理程序。在這種情況下,可以使用**
once
**函數(shù)來(lái)確保這些代碼只會(huì)被執(zhí)行一次,避免不必要的重復(fù)操作。
在VSCode中, once
用的非常頻繁,通過(guò)查看 reference
我們可以看到非常多的使用:
once的注意事項(xiàng)
this指針問(wèn)題
在 once
函數(shù)內(nèi)部,定義了一個(gè)名為 _this
的變量,它保存了函數(shù)的 this
關(guān)鍵字。這是因?yàn)?,在使?apply
或 call
方法調(diào)用函數(shù)時(shí),需要確保函數(shù)中的 this
關(guān)鍵字被正確地綁定。如果沒(méi)有保存 _this
變量,而是直接使用 this
關(guān)鍵字,可能會(huì)導(dǎo)致 this
關(guān)鍵字在多次調(diào)用中被意外地修改,從而導(dǎo)致錯(cuò)誤或異常。
在使用 once
函數(shù)時(shí),如果原始函數(shù)需要使用 this
關(guān)鍵字,需要確保 this
關(guān)鍵字被正確地綁定??纯匆韵麓a:
class Counter { private count = 0; constructor(private readonly name: string) {} increment() { console.log(`${this.name}: Count = ${++this.count}`); } } const counter1 = new Counter('Counter 1'); const counter2 = new Counter('Counter 2'); const incrementOnce = once(counter1.increment); incrementOnce.call(counter1); // 輸出 "Counter 1: Count = 1" incrementOnce.call(counter2); // 輸出 "Counter 1: Count = 2",而不是 "Counter 2: Count = 1" incrementOnce.call(counter1); // 輸出 "Counter 1: Count = 2"
在上述代碼中,如果我們?cè)诙啻握{(diào)用 incrementOnce
函數(shù)時(shí),使用了不同的 this
關(guān)鍵字,可能會(huì)導(dǎo)致輸出結(jié)果不正確。例如,上述代碼中的第二次調(diào)用 incrementOnce
函數(shù)時(shí),使用了 counter2
作為 this
關(guān)鍵字,而實(shí)際上 incrementOnce
函數(shù)中保存的 this
關(guān)鍵字是 counter1
,因此輸出結(jié)果為 "Counter 1: Count = 2",而不是 "Counter 2: Count = 1"。
因此,在使用 once
函數(shù)時(shí),需要確保原始函數(shù)能夠正確地處理 this
關(guān)鍵字,并且在調(diào)用 once
函數(shù)時(shí),應(yīng)該指定正確的 this
關(guān)鍵字,以避免意外的錯(cuò)誤或異常。
小結(jié)
本文對(duì) once
函數(shù)進(jìn)行了詳細(xì)的剖析,包括其背景、實(shí)現(xiàn)原理和應(yīng)用場(chǎng)景。在實(shí)際開發(fā)中,once
函數(shù)可以用于緩存函數(shù)的結(jié)果、避免重復(fù)網(wǎng)絡(luò)請(qǐng)求以及確保只運(yùn)行一次的初始化代碼。在使用 once
函數(shù)時(shí),需要注意原始函數(shù)的 this
關(guān)鍵字的綁定,以避免意外的錯(cuò)誤或異常。
在我們的日常開發(fā)中,見過(guò)太多的代碼為了保證只執(zhí)行一次,在本地定一個(gè)類似 flag
的變量來(lái)控制,這種寫法非常不優(yōu)雅,在這種場(chǎng)景下,使用 once
函數(shù)是一個(gè)更好的選擇。
以上就是vscode工具函數(shù)once使用示例深入剖析的詳細(xì)內(nèi)容,更多關(guān)于vscode工具函數(shù)once的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序 向左滑動(dòng)刪除功能的實(shí)現(xiàn)
這篇文章主要介紹了微信小程序 向左滑動(dòng)刪除功能的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-03-03yocto queue微型隊(duì)列數(shù)據(jù)結(jié)構(gòu)源碼解讀
這篇文章主要為大家介紹了yocto queue微型隊(duì)列數(shù)據(jù)結(jié)構(gòu)源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12fetch-event-source庫(kù)使用源碼學(xué)習(xí)
這篇文章主要為大家介紹了fetch-event-source庫(kù)源碼學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09Three.js?Interpolant實(shí)現(xiàn)動(dòng)畫插值
這篇文章主要為大家介紹了Three.js?Interpolant實(shí)現(xiàn)動(dòng)畫插值示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02ECMAScript 6對(duì)象的擴(kuò)展實(shí)現(xiàn)示例
這篇文章主要為大家介紹了ECMAScript 6對(duì)象的擴(kuò)展實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08微信小程序 出現(xiàn)錯(cuò)誤:{"baseresponse":{"errcode":-80002,"errmsg":""}}解決
這篇文章主要介紹了微信小程序 出現(xiàn)錯(cuò)誤:{"baseresponse":{"errcode":-80002,"errmsg":""}}解決辦法的相關(guān)資料,需要的朋友可以參考下2017-02-02