最近在看<JavaScript高級程序設計>中看到arguments.callee這個屬性,才知道JavaScript裏面的遞歸有這麼多的坑。之前都不知道,今天就整理一下,咱們先從最初開始吧。
這裏就不用說定義了,我們直接上代碼,在正常模式下。es6
function factorial(num){ if(num<=1){ return 1; }else{ return num * factorial(num-1); } }
上面是一個典型的遞歸調用,可可是,它有一個問題。函數
var anotherFactorial = factorial; factorial = null; alert(anotherFactorial(4));//報錯
遞歸函數就是在一個函數裏經過名字調用自身的狀況(仍是得說一下)。正常的狀況下咱們這樣作沒有問題了,但是關鍵是JavaScript
語言和其餘的語言不太同樣,函數名稱只是一個指針,它並非函數的實體對象。因此若是咱們把這個指針改變了,那麼在函數裏面的指針調用就不是它本身了,上面的例子裏,咱們直接把它幹掉了。讓它指向了空,它直接就奔潰了。優化
這裏就引出了一個重要的屬性:spa
callee
是arguments
對象的一個屬性,arguments.callee
值一個指向正在執行的函數的指針。所以它能夠實現對函數的遞歸調用。設計
例如:代理
function factorial(num){ if(num<=1){ return 1; }else{ return num * arguments.callee(num-1); } }
經過使用arguments.callee
代理函數名,能夠確保不管怎樣調用函數都不會出問題。所以在正常模式下,使用這種方式會更加保險。指針
可是在嚴格模式下,調用上面的arguments.callee
卻會致使錯誤,由於嚴格模式不支持arguments
。那怎麼樣辦呢 ?code
arguments.callee
怎麼辦 ?經過使用命名錶達式也但是實現一樣的效果。看代碼:對象
var factorial = (function f(num){ if(num<=1){ return 1; }else{ return num * f(num-1); } });
上面的代碼建立了一個名爲f()
的命名錶達式,而後將它賦值給變量factorial
。這樣的話,即便把變量的變成另外一個變量,也不會影響我內部本身的調用。f
函數名字仍然有效。因此遞歸函數調用照樣能正確執行。遞歸
如今咱們把ECMA
的版本升級到6.
ES6
的狀況下呢?在ES6
的狀況下,咱們能夠寫成另外的方式來實現。例如:
const factorial = (function f(num){ if(num<=1){ return 1; }else{ return num * f(num-1); } });
咱們把var
升級爲const
,讓這個變量變成常量,這樣變量也改變不了。咱們用箭頭函數來替代上面的命名函數。
const factorial =num=>{ if(num<=1){ return 1; }else{ return num * factorial(num-1); } }
常量沒法更改,因此咱們能夠寫成上面的代碼。可是你覺得代碼就沒有問題了嗎???
咱們這樣調用一下:
factorial(100000);
而後報下面的錯誤,RangeError
:超出了最大調用堆棧大小
RangeError: Maximum call stack size exceeded at factorial (H:\company_work_space\Demos\Demo1.js:40:18) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22) at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
下一步就是怎麼解決這個問題。答案是使用尾調用優化。
什麼是尾調用呢?能夠先看這個什麼是尾調用?