vscode工具函數once使用示例深入剖析
背景
once 函數的起源可以追溯到函數式編程。在函數式編程中,函數被視為不可變的,這意味著它們不應修改任何狀態(tài)或引用任何狀態(tài)。因此,在函數式編程中,通常需要一些技巧來處理一些常見問題,例如避免在多次調用相同函數時進行冗余計算。
once 函數是解決此問題的一種方法。它可以將函數轉換為只能調用一次的函數,并使用一些技巧來避免冗余計算。使用 once 函數可以減少計算時間和資源的消耗,并提高應用程序的性能。
once 函數在現(xiàn)代 JavaScript 庫和框架中非常常見,例如 lodash。它們提供了許多內置的 once 函數來處理各種場景和問題。在實際開發(fā)中,我們可以使用這些函數來提高代碼的可維護性和可讀性,避免冗余計算和網絡請求,并提高應用程序的性能。
VSCode中的實現(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;
}
這個實現(xiàn)比較簡單,但還是詳細分析解釋一下代碼
- 函數簽名:
once<T extends Function>(this: unknown, fn: T): T。該函數使用了泛型參數**T,表示被封裝的原始函數的類型。它還定義了一個this參數,表示封裝函數中的this關鍵字的類型為unknown,以及一個fn**參數,表示被封裝的原始函數。 - 緩存結果:在函數內部,定義了三個變量。**
_this變量引用了函數中的this關鍵字,并將其保存在變量中。didCall變量用于跟蹤函數是否已經被調用過。result**變量用于保存函數的結果。 - 返回新函數:函數內部返回了一個匿名函數,它接受任意數量的參數,并將其傳遞給原始函數。在函數內部,首先檢查函數是否已經被調用過。如果是,則直接返回之前保存的結果。否則,將**
didCall**標記為已調用,并調用原始函數并保存結果。最后,返回結果。 - 類型斷言:函數的返回值是一個匿名函數,但是它的類型需要與原始函數相同。因此,使用了一個類型斷言將匿名函數的類型強制轉換為泛型參數**
T**。
lodash的實現(xiàn)
lodash 到目前的版本已經是高度封裝了,它的源碼可以在**github.com/lodash/loda…**看到:
function once(func) {
return before(2, func)
}
它本身是調用了 before 函數, before 是一個經過高度抽象的函數,它在被調用次數達到指定次數之前,會繼續(xù)執(zhí)行傳入的函數,而在達到指定次數時,會返回最后一次執(zhí)行傳入函數的結果:
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
}
}
對于 lodash 這樣的工具庫而言,它的抽象層次要比 vscode 更高,但實現(xiàn)的原理是相同的,核心都是利用閉包,通過內部變量的狀態(tài)來判斷函數是否已經被調用過,從而保證原始函數只被執(zhí)行一次。
once的應用
**once**函數是一個常見的JavaScript函數,它用于確保一個函數只能被調用一次。這個函數在以下幾個場景下非常有用:
- 緩存函數的結果:當一個函數需要執(zhí)行復雜的計算時,我們可以使用**
once**函數來確保它只會被調用一次,并將結果緩存下來。在之后的調用中,函數會直接返回緩存的結果,而不會再次執(zhí)行計算。這可以節(jié)省計算時間和資源,并提高應用程序的性能。 - 避免重復網絡請求:當我們需要向服務器發(fā)送請求時,可以使用**
once**函數來確保只發(fā)送一次請求,并在之后的調用中直接返回結果。這可以避免發(fā)送重復的網絡請求,并提高應用程序的響應速度。 - 確保只運行一次的初始化代碼:有時候我們需要在應用程序啟動時執(zhí)行一些初始化代碼,例如創(chuàng)建全局變量或注冊事件處理程序。在這種情況下,可以使用**
once**函數來確保這些代碼只會被執(zhí)行一次,避免不必要的重復操作。
在VSCode中, once 用的非常頻繁,通過查看 reference 我們可以看到非常多的使用:

once的注意事項
this指針問題
在 once 函數內部,定義了一個名為 _this 的變量,它保存了函數的 this 關鍵字。這是因為,在使用 apply 或 call 方法調用函數時,需要確保函數中的 this 關鍵字被正確地綁定。如果沒有保存 _this 變量,而是直接使用 this 關鍵字,可能會導致 this 關鍵字在多次調用中被意外地修改,從而導致錯誤或異常。
在使用 once 函數時,如果原始函數需要使用 this 關鍵字,需要確保 this 關鍵字被正確地綁定??纯匆韵麓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"
在上述代碼中,如果我們在多次調用 incrementOnce 函數時,使用了不同的 this 關鍵字,可能會導致輸出結果不正確。例如,上述代碼中的第二次調用 incrementOnce 函數時,使用了 counter2 作為 this 關鍵字,而實際上 incrementOnce 函數中保存的 this 關鍵字是 counter1,因此輸出結果為 "Counter 1: Count = 2",而不是 "Counter 2: Count = 1"。
因此,在使用 once 函數時,需要確保原始函數能夠正確地處理 this 關鍵字,并且在調用 once 函數時,應該指定正確的 this 關鍵字,以避免意外的錯誤或異常。
小結
本文對 once 函數進行了詳細的剖析,包括其背景、實現(xiàn)原理和應用場景。在實際開發(fā)中,once 函數可以用于緩存函數的結果、避免重復網絡請求以及確保只運行一次的初始化代碼。在使用 once 函數時,需要注意原始函數的 this 關鍵字的綁定,以避免意外的錯誤或異常。
在我們的日常開發(fā)中,見過太多的代碼為了保證只執(zhí)行一次,在本地定一個類似 flag 的變量來控制,這種寫法非常不優(yōu)雅,在這種場景下,使用 once 函數是一個更好的選擇。
以上就是vscode工具函數once使用示例深入剖析的詳細內容,更多關于vscode工具函數once的資料請關注腳本之家其它相關文章!
相關文章
Three.js?Interpolant實現(xiàn)動畫插值
這篇文章主要為大家介紹了Three.js?Interpolant實現(xiàn)動畫插值示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02
微信小程序 出現(xiàn)錯誤:{"baseresponse":{"errcode":-80002,"errmsg":""}}解決
這篇文章主要介紹了微信小程序 出現(xiàn)錯誤:{"baseresponse":{"errcode":-80002,"errmsg":""}}解決辦法的相關資料,需要的朋友可以參考下2017-02-02

