尾呼叫優化
阿新 • • 發佈:2022-04-03
今天在面試時遇到這樣一個筆試題目,如何優化以下一段程式碼,實現尾呼叫優化?
`
function factorial(n) { if (n <= 1) { return 1; return n * factorial(n - 1); }`
答案:
之前在《紅寶書》以及《深入理解ES6》看到過尾呼叫的這部分內容,但確實忘記如何修改這段程式碼了,只記得要在最後只返回一個函式,而不能進行任何的額外操作。所以此題並沒有完全回答正確。
回來也是好好複習了以下這部分的內容,以備下次遇到這型別不知道如何回答。
首先尾呼叫優化是在ES6才有的引擎優化,它改變了尾部呼叫的系統。在呼叫函式的結尾是另一個函式的最後語句。如下:
在 ES5 引擎中實現的尾呼叫,其處理就像其他函式呼叫一樣:一個新的棧幀( stack frame)被建立並推到呼叫棧之上,用於表示該次函式呼叫。這意味著之前每個棧幀都被保留在記憶體中,當呼叫棧太大時會出問題。
ES6 在嚴格模式下會為特定尾呼叫減少呼叫棧的大小(非嚴格模式的尾呼叫則保持不變)。當滿足以下條件時,尾呼叫優化會清除當前棧幀並再次利用它,而不是為尾呼叫建立新的棧幀:
1. 尾呼叫不能引用當前棧幀中的變數(意味著該函式不能是閉包);
2. 進行尾呼叫的函式在尾呼叫返回結果後不能做額外操作;
3. 尾呼叫的結果作為當前函式的返回值。
"use strict";
function doSomething() {
// 未被優化:缺少 return
doSomethingElse();
}
"use strict";
function doSomething() {
// 未被優化:呼叫並不在尾部
var result = doSomethingElse();
return result;
}
"use strict";
function doSomething() {
var num = 1,
func = () => num;
// 未被優化:此函式是閉包
return func();
}
尾呼叫優化允許某些函式的呼叫被優化,以保持更小的呼叫棧、使用更少的記憶體,並防止堆疊溢位。當能進行安全優化時,它會由引擎自動應用。不過你可以考慮重寫遞迴函式,以便能夠利用這種優化。