目錄
一惶看、 函數(shù)參數(shù)的默認(rèn)值
二、rest參數(shù)
三六孵、嚴(yán)格模式
四纬黎、name 屬性
五、箭頭函數(shù)
六劫窒、雙冒號運(yùn)算符(目前報錯本今,只是提案。)
七主巍、重點(diǎn): 尾調(diào)用優(yōu)化冠息,尾遞歸優(yōu)化( Fibonacci 數(shù)列)
八、函數(shù)參數(shù)尾逗號
尾遞歸
總結(jié)一下孕索,遞歸本質(zhì)上是一種循環(huán)操作逛艰。純粹的函數(shù)式編程語言沒有循環(huán)操作命令,所有的循環(huán)都用遞歸實(shí)現(xiàn)搞旭,這就是為什么尾遞歸對這些語言極其重要散怖。對于其他支持“尾調(diào)用優(yōu)化”的語言(比如 Lua,ES6)选脊,只需要知道循環(huán)可以用遞歸代替杭抠,而一旦使用遞歸,就最好使用尾遞歸恳啥。
下面是一個正常的遞歸函數(shù)偏灿。
function sum(x, y) {
if (y > 0) {
return sum(x + 1, y - 1);
} else {
return x;
}
}
sum(1, 100000)
// Uncaught RangeError: Maximum call stack size exceeded(…)
上面代碼中,sum是一個遞歸函數(shù)钝的,參數(shù)x是需要累加的值翁垂,參數(shù)y控制遞歸次數(shù)铆遭。一旦指定sum遞歸 100000 次,就會報錯沿猜,提示超出調(diào)用棧的最大次數(shù)枚荣。
蹦床函數(shù)(trampoline)可以將遞歸執(zhí)行轉(zhuǎn)為循環(huán)執(zhí)行。
function trampoline(f) {
while (f && f instanceof Function) {
f = f();
}
return f;
}
上面就是蹦床函數(shù)的一個實(shí)現(xiàn)啼肩,它接受一個函數(shù)f作為參數(shù)橄妆。只要f執(zhí)行后返回一個函數(shù),就繼續(xù)執(zhí)行祈坠。注意害碾,這里是返回一個函數(shù),然后執(zhí)行該函數(shù)赦拘,而不是函數(shù)里面調(diào)用函數(shù)慌随,這樣就避免了遞歸執(zhí)行,從而就消除了調(diào)用棧過大的問題躺同。
然后阁猜,要做的就是將原來的遞歸函數(shù),改寫為每一步返回另一個函數(shù)蹋艺。
function sum(x, y) {
if (y > 0) {
return sum.bind(null, x + 1, y - 1);
} else {
return x;
}
}
上面代碼中剃袍,sum函數(shù)的每次執(zhí)行,都會返回自身的另一個版本车海。
現(xiàn)在笛园,使用蹦床函數(shù)執(zhí)行sum,就不會發(fā)生調(diào)用棧溢出侍芝。
trampoline(sum(1, 100000))
// 100001
蹦床函數(shù)并不是真正的尾遞歸優(yōu)化研铆,下面的實(shí)現(xiàn)才是。
function tco(f) {
var value;
var active = false;
var accumulated = [];
return function accumulator() {
accumulated.push(arguments);
if (!active) {
active = true;
while (accumulated.length) {
value = f.apply(this, accumulated.shift());
}
active = false;
return value;
}
};
}
var sum = tco(function(x, y) {
if (y > 0) {
return sum(x + 1, y - 1)
}
else {
return x
}
});
sum(1, 100000)
// 100001
上面代碼中州叠,tco函數(shù)是尾遞歸優(yōu)化的實(shí)現(xiàn)棵红,它的奧妙就在于狀態(tài)變量active。默認(rèn)情況下咧栗,這個變量是不激活的逆甜。一旦進(jìn)入尾遞歸優(yōu)化的過程,這個變量就激活了致板。然后交煞,每一輪遞歸sum返回的都是undefined,所以就避免了遞歸執(zhí)行斟或;而accumulated數(shù)組存放每一輪sum執(zhí)行的參數(shù)素征,總是有值的,這就保證了accumulator函數(shù)內(nèi)部的while循環(huán)總是會執(zhí)行。這樣就很巧妙地將“遞歸”改成了“循環(huán)”御毅,而后一輪的參數(shù)會取代前一輪的參數(shù)根欧,保證了調(diào)用棧只有一層。