1. 是什麼?javascript
函數末尾只調用自身稱爲尾遞歸。java
2. 爲何?es6
遞歸函數在調用時會在內存中保存調用位置和內部變量信息,造成一個調用棧。若是不加優化,有可能同時保存成百上千個調用記錄。很容易發生棧溢出的錯誤。函數
尾調用函數因爲是函數的最後一步操做,因此不須要保留外層函數的調用記錄,由於調用位置和內部變量信息都不須要再用到了,只要直接用內存的調用記錄取代外層的調用記錄就能夠了。因此不會發生棧溢出的錯誤。優化
3. 怎麼辦?this
實現尾遞歸只須要咱們在原來的函數基礎上追加一個參數用來保存遞歸循環的值。固然這樣會大大增長函數的有雅興。因此優化方式能夠有:spa
function tailFactorial(n, total) { if (n === 1) return total; return tailFactorial(n - 1, n * total); } function factorial(n) { return tailFactorial(n, 1); } factorial(5) // 120
function currying(fn, n) { return function (m) { return fn.call(this, m, n); }; } function tailFactorial(n, total) { if (n === 1) return total; return tailFactorial(n - 1, n * total); } const factorial = currying(tailFactorial, 1); factorial(5) // 120
function factorial(n, total = 1) { if (n === 1) return total; return factorial(n - 1, n * total); } factorial(5) // 120