“尾遞歸優(yōu)化”的含義是:如果遞歸函數(shù)屬于尾遞歸,那么運(yùn)行時(shí)會優(yōu)化其調(diào)用過程。優(yōu)化主要針對調(diào)用棧,將多層調(diào)用,轉(zhuǎn)化為一層調(diào)用。
遞歸的概念很簡單,就是函數(shù)調(diào)用自身。而所謂的“尾遞歸”就是在函數(shù)體的最后才調(diào)用自身。例如:
var fn = function(m, n) {
var x = m + 1
var y = n * 2
fn(x, y)
}
fn(1, 2)
在上述例子中,函數(shù)fn在其函數(shù)體的最后又調(diào)用了自己,fn。這就叫尾遞歸。
遞歸調(diào)用其實(shí)跟普通函數(shù)調(diào)用并沒有本質(zhì)的不同,都是函數(shù)調(diào)用函數(shù)。但是普通函數(shù)調(diào)用的層次一般不會太深,這跟設(shè)計(jì)時(shí)的邏輯分層有關(guān)。但是遞歸就不一樣了,一不小心就可能產(chǎn)生很多層的調(diào)用。試想一下,如果一個(gè)遞歸一直沒有返回直接結(jié)果,而是一直在調(diào)用自身。那么每次調(diào)用,函數(shù)中的變量、參數(shù)都會壓棧。由于沒有返回,這些棧空間得不到釋放,棧很快就會溢出。
當(dāng)然,設(shè)計(jì)好的遞歸調(diào)用一般不會產(chǎn)生這樣的情形。大多數(shù)類似的錯(cuò)誤都會在開發(fā)階段發(fā)現(xiàn)并解決。比較常見的情形是遞歸層次較多,棧空間被占用了很多。
而如果是尾遞歸,由于函數(shù)返回的是最后的語句,也就是說返回值只跟最后的調(diào)用有關(guān)系,那么函數(shù)中的變量顯然就沒有必要保存了。因此針對上述例子,最終可以優(yōu)化成:
fn(2, 4)