js 舉例說明js中什麼是尾呼叫優化

2021-10-13 19:36:12 字數 1059 閱讀 9207

寫在前面

上次介紹了什麼是尾呼叫以及怎麼準確快速的判別乙個函式呼叫是否為尾呼叫。那麼,我們判別尾呼叫的意義是什麼呢?做什麼事情總歸有個目的,那麼今天我們就來系統的介紹一下尾呼叫的意義,或者說尾呼叫有什麼用吧。

2. 尾呼叫優化

我們知道,函式的呼叫會在記憶體中生成乙個「呼叫幀」(call frame),儲存著函式的呼叫位置和內部變數等資訊。如果在函式a的內部呼叫函式b,那麼在a的呼叫幀上方還會生成乙個b的呼叫幀。等到函式b執行結束,將結果返回到a,b的呼叫幀才會消失。如果函式b的內部還呼叫函式c,那麼在b的呼叫幀上方又會生成乙個c的呼叫幀,以此類推。所有的呼叫幀就形成了乙個「呼叫棧」(call stack)。

我們知道,尾呼叫是函式的最後一步操作,外部函式的呼叫位置和其內部變數資訊都不會再用到了,所以不需要保留外部函式的呼叫幀了,直接用內層函式的呼叫幀取代外層函式的呼叫幀即可。

如果所有的函式都是尾呼叫,那麼完全可以做到每次執行時的呼叫幀只有一項,這將大大的節省記憶體,更不可能發生記憶體溢位,這就是討論尾呼叫的意義所在。

所謂的「尾呼叫優化」,其實就是保證在函式執行時只保留內層函式的呼叫幀,換句話說,就是用內層函式的呼叫幀取代外部函式的呼叫幀,即執行時記憶體中只儲存一項呼叫幀。

3. 如何做到尾呼叫優化

通過上面的討論,我們知道了,只要外部函式的呼叫幀被內層函式的呼叫幀取代即可做到「尾呼叫優化」。同時,我們也知道呼叫幀是用來儲存函式呼叫位置和內部變數資訊的,所以,要想讓內層函式的呼叫幀取代外部函式的呼叫幀,只需要保證,在呼叫內層函式時,不再用到和外部函式有關的一切資訊即可(不再用到外部函式的內部變數)。

如此,我們總結出只有內層函式在被呼叫時不再用到外部函式的內部變數,才能做到「尾呼叫優化」。

先來,看乙個例子:

function f(a) 

return g(a)

}

上述例子,我們明顯可以看出這是典型的尾呼叫,那麼這有沒有做到「尾呼叫優化」呢?很明顯,可以看出在呼叫內部函式g的時候,其內部用到外部函式f 的內部變數b,故在函式g 被呼叫時,g 的呼叫幀並不能取代外部函式f 的呼叫幀,所以這不是「尾呼叫優化」。

與歌謠一起通關前端面試題

什麼是競態條件?舉例說明

當兩個執行緒競爭同一資源時,如果對資源的訪問順序敏感,就稱存在競態條件。導致競態條件發生的 區稱作臨界區。在臨界區中使用適當的同步就可以避免競態條件。臨界區實現方法有兩種,一種是用synchronized,一種是用lock顯式鎖實現。eg 來自 class counter 觀察執行緒a和b交錯執行會...

什麼是拆箱和裝箱 舉例說明

1.裝箱,值型別向引用型別轉換 在託管堆中分配記憶體,分配的記憶體量是型別各字段所需的記憶體量 型別物件指標所需的記憶體量 同步塊索引所需的記憶體量。值型別的字段複製到分配好的記憶體中 返回物件位址,現在物件位址是物件引用 2.拆箱,引用型別向值型別轉換 獲取已裝箱型別中的未裝箱部分,也就是物件的原...

舉例說明什麼是隱馬爾科夫模型(HMM)

維基百科對隱馬爾可夫模型的定義 隱馬爾可夫模型 hidden markov model,hmm 是統計模型,它用來描述乙個含有隱含未知引數的馬爾可夫過程。其難點是從可觀察的引數中確定該過程的隱含引數。然後利用這些引數來作進一步的分析,例如模式識別。在正常的馬爾可夫模型中,狀態對於觀察者來說是直接可見...