JS遞迴--你不知道的匿名遞迴函式細節
阿新 • • 發佈:2019-01-04
遞迴
- 遞迴函式必須能夠引用它本身
- 遞迴是函式自己呼叫自己
- 一般都需要一個結束的條件
遞迴的認識
- 寫出一個數的階乘
function fn(n){
if(n===1){
return 1
}
return n*fn(n-1)
}
console.log(fn(4)) //4的階乘
- 遞迴的報錯
一般沒有寫結束條件(如上面的if(n===1){return 1})的情況下報錯
Uncaught RangeError: Maximum call stack size exceeded
即記憶體溢位:超過了最大的堆疊大小
匿名遞迴函式(jQuery下個知識點)
- 很典型的,函式通過自己的名字呼叫自己(如上面的案例)
- 然而,匿名函式是沒有名稱。因此如果沒有可訪問的變數指向該函式,唯一能引用它的方式就是通過 arguments.callee
function createFn(){
return function(n){
if(n===1){
return 1
}
return n*arguments.callee(n-1)
}
}
var f1 = createFn()
console.log(f1(4))
然而,這實際上是一個非常糟糕的解決方案,另外,遞迴呼叫在一些情況會獲取到一個不同的this值
var global = this;
function createFn(){
return function(n){
if(n===1){
if (this !== global) {
alert("This is: " + this); //執行
} else {
alert("This is the global");
}
return 1
}
return n*arguments.callee(n-1)
}
}
var f1 = createFn()
console. log(f1(4))
jQuery匿名遞迴函式
- 我們在使用 jQuery大部分都會使用到回撥函式
- jQ除了相容性好,主要突出的兩個特點就是鏈式程式設計和隱式迭代
- 那麼 arguments.callee就顯得很有必要
- 我們通過案例說明;準備四張圖片,並給它設定大小,引入jquery.js
<input type="button" value="隱藏動畫" id="btn1"/>
<input type="button" value="顯示動畫" id="btn2"/>
<div>
<img src="images/1.jpg"/>
<img src="images/2.jpg"/>
<img src="images/3.jpg"/>
<img src="images/4.jpg"/>
</div>
效果如下:
接下來需求是:我們點選隱藏動畫從最後一張圖片在一定時間開始隱藏完畢後,在隱藏倒數第三張,倒數第三張圖片隱藏完畢後,在隱藏第二張…
很累贅的程式碼演示(記得引入jQuery)
$('#btn1').on('click',function(){
$('img').eq(3).hide(1000,function(){
$(this).prev().hide(800,function(){
$(this).prev().hide(800,function(){
$(this).prev().hide(800)
})
})
})
})
雖然能解決問題,但是是一百張圖片,或則其它情況呢?這樣的程式碼大量重複,冗餘和累贅,不是良好的程式碼風格,封裝起來一層巢狀一層,會極大影響程式碼可讀性和邏輯
從上面可以看出,匿名函式自己呼叫自己,正好符合遞迴,但是封裝成一個命名函式,影響程式碼可讀性和邏輯,這個時候arguments.callee就是很好的解決方案
$('#btn1').on('click',function(){
$('img').eq(3).hide(1000,function(){
$(this).prev().hide(800,arguments.callee);
})
})
這樣程式碼量少,看起來高大上了很多,具有可讀性和邏輯性
如何使用遞迴
- 兩個必要條件: 遞迴方程,遞迴結束條件
- 一般遞迴是從後往前推,可以根據結束條件和函式引數的變化來死開
- 遞迴是函式體呼叫自己,一般都是在特定的情況下使用:
案例:求菲波那切數列的第n個數是多少
function Fibonacci(n){
if(n==1 || n==2){
return 1
}
return Fibonacci(n-1) + Fibonacci(n-2)
}
console.log(Fibonacci(5))