遞歸函數大家都應該比較熟吧?那麼,如何在JavaScript中書寫一個完美的遞歸函數呢?且聽我娓娓道來。 遞歸函數 寫的時候,查了一下維基百科對遞歸函數的定義,恕我愚鈍,簡直太深奧了!所以,我還是簡單的說說我對遞歸函數的理解吧。遞歸函數,說白了就是在函數內部引用函數自身,最終到給定的遞歸結束條件時回 ...
遞歸函數大家都應該比較熟吧?那麼,如何在JavaScript中書寫一個完美的遞歸函數呢?且聽我娓娓道來。
遞歸函數
寫的時候,查了一下維基百科對遞歸函數的定義,恕我愚鈍,簡直太深奧了!所以,我還是簡單的說說我對遞歸函數的理解吧。遞歸函數,說白了就是在函數內部引用函數自身,最終到給定的遞歸結束條件時回溯。當然,你也可以不給定結束條件,死了別掛我~(╯﹏╰)~。
簡單說就是有兩個條件:
1. 在函數內部引用自身。
2. 每個遞歸函數里必定有一個終止條件。
來個小李子:
function test(num){ if(num <= 1){ return 1; }else{ return num * test(num-1); } } var a = test; console.log(a(6)); // 1
好了,不錯,一個堪稱經典的遞歸求階乘的函數誕生了。事情肯定不會這麼順利,一定是個圈套。我們來如下調用以下看看會怎麼樣?
var a = test; test = null; console.log(a(6)); // Uncaught TypeError: test is not a function
居然報錯了
回過頭去看看我們是如何調用的。發現問題了吧!我們把test賦給了a,然後把test給回收掉了。為什麼會出錯呢?因為像function這種賦值其實是引用傳遞,只是把指向函數的指針(這裡說地址也行)賦給a了。但我們把test賦值為null的時候,函數都已經被回收了,拿什麼來執行?知道問題所在了,我決定換種方式來定義:
function test(num){ if(num <= 1){ return 1; }else{ return num * arguments.callee(--num); } }
然後測試一下:
var test = fun; fun = null; console.log(test(7));
用arguments.callee可解決問題,這是一個指向正在執行的函數的指針,arguments.callee返回正在被執行的對現象。
但是在某一天,當我實際碼代碼的時候,問題又出現了。什麼問題呢?我們來看一下:
Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
╮(╯▽╰)╭哎!可憐啊!因為我使用了"use strict"!嚴格模式下是不允許的。。。
好吧!繼續想辦法!既然不能使用arguments.callee(),那還是想想其他的方式吧。
var fun = (function f(num){ if(num <= 1){ return 1; } else{ return num * f(--num); } });
然後我測試了以下,神奇的通過了,暫時沒有發現任何問題!
為什麼呢?因為我們使用了“()”,巧妙地使用命名函數表達式來達到了同樣的效果。
<( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)>