1. 程式人生 > 其它 >尾呼叫優化

尾呼叫優化

今天在面試時遇到這樣一個筆試題目,如何優化以下一段程式碼,實現尾呼叫優化?

`

function factorial(n) {     if (n <= 1) {         return 1;           return n * factorial(n - 1);      }

`

 

答案:

function factorial(n, p = 1) {     if (n <= 1) {         return 1 * p;     } else {         let result = n * p;         // 被優化         return factorial(n - 1, result);     } }

 

 

之前在《紅寶書》以及《深入理解ES6》看到過尾呼叫的這部分內容,但確實忘記如何修改這段程式碼了,只記得要在最後只返回一個函式,而不能進行任何的額外操作。所以此題並沒有完全回答正確。

回來也是好好複習了以下這部分的內容,以備下次遇到這型別不知道如何回答。

首先尾呼叫優化是在ES6才有的引擎優化,它改變了尾部呼叫的系統。在呼叫函式的結尾是另一個函式的最後語句。如下:

function doSomething() {     return doSomethingElse(); // 尾呼叫 }

 

在 ES5 引擎中實現的尾呼叫,其處理就像其他函式呼叫一樣:一個新的棧幀( stack frame)被建立並推到呼叫棧之上,用於表示該次函式呼叫。這意味著之前每個棧幀都被保留在記憶體中,當呼叫棧太大時會出問題。 

ES6 在嚴格模式下會為特定尾呼叫減少呼叫棧的大小(非嚴格模式的尾呼叫則保持不變)。當滿足以下條件時,尾呼叫優化會清除當前棧幀並再次利用它,而不是為尾呼叫建立新的棧幀: 

 

1. 尾呼叫不能引用當前棧幀中的變數(意味著該函式不能是閉包);
2. 進行尾呼叫的函式在尾呼叫返回結果後不能做額外操作;
3. 尾呼叫的結果作為當前函式的返回值。

 

正確示例: "use strict"; function doSomething() {     // 被優化     return doSomethingElse(); }   錯誤示例: "use strict"; function doSomething() {     // 未被優化:缺少 return     doSomethingElse(); }
"use strict"; function doSomething() {     // 未被優化:在返回之後還要執行加法     return 1 + doSomethingElse(); } "use strict"; function doSomething() {     // 未被優化:呼叫並不在尾部     var result = doSomethingElse();     return result; }   "use strict"; function doSomething() {     var num = 1,         func = () => num;     // 未被優化:此函式是閉包     return func(); }

尾呼叫優化允許某些函式的呼叫被優化,以保持更小的呼叫棧、使用更少的記憶體,並防止堆疊溢位。當能進行安全優化時,它會由引擎自動應用。不過你可以考慮重寫遞迴函式,以便能夠利用這種優化。