1. 程式人生 > >JS遞迴--你不知道的匿名遞迴函式細節

JS遞迴--你不知道的匿名遞迴函式細節

遞迴

  • 遞迴函式必須能夠引用它本身
  • 遞迴是函式自己呼叫自己
  • 一般都需要一個結束的條件

遞迴的認識

  • 寫出一個數的階乘
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匿名遞迴函式

  1. 我們在使用 jQuery大部分都會使用到回撥函式
  2. jQ除了相容性好,主要突出的兩個特點就是鏈式程式設計和隱式迭代
  3. 那麼 arguments.callee就顯得很有必要
  4. 我們通過案例說明;準備四張圖片,並給它設定大小,引入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);
			})
		})

這樣程式碼量少,看起來高大上了很多,具有可讀性和邏輯性

如何使用遞迴

  1. 兩個必要條件: 遞迴方程,遞迴結束條件
  2. 一般遞迴是從後往前推,可以根據結束條件和函式引數的變化來死開
  3. 遞迴是函式體呼叫自己,一般都是在特定的情況下使用:
    案例:求菲波那切數列的第n個數是多少
function Fibonacci(n){
		if(n==1 || n==2){
			return 1
		}
		return Fibonacci(n-1) + Fibonacci(n-2)
	}
	console.log(Fibonacci(5))