讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議30:使用遞歸模式 >

建議30:使用遞歸模式

複雜算法通常比較容易使用遞歸實現。很多傳統算法正是通過遞歸實現的,如階乘函數。


function factorial(n){

if(n==0){

return 1;

}else{

return n*factorial(n-1);

}

}


遞歸函數的問題:錯誤定義或缺少終結條件會導致函數長時間運行,使瀏覽器出現假死現象。此外,遞歸函數還會受到瀏覽器調用棧大小的限制。

JavaScript引擎所支持的遞歸數量與JavaScript調用棧大小直接相關。只有IE例外,因為它的調用棧與可用系統內存相關,而其他瀏覽器有固定的調用棧限制。當使用了太多的遞歸,超過最大調用棧尺寸時,瀏覽器會彈出錯誤信息。

調用棧溢出錯誤可以用try catch語句捕獲。異常類型因瀏覽器而不同:在Firefox中,它是一個InternalError錯誤;在Safari和Chrome中,它是一個RangeError錯誤;在IE中會拋出一個一般性的Error類型;在Opera中不拋出錯誤,但會終止JavaScript引擎。正確處理這些錯誤的方法如下:


try{

recurse;

}catch(ex){

alert("errorInfo");

}


當出現調用棧尺寸限制的問題時,第一步應該定位在代碼中的遞歸實例上。為此,有兩個遞歸模式可供選擇。

第一種是直接遞歸模式,即一個函數調用自身。當發生錯誤時,這種模式比較容易定位。其一般模式如下:


function recurse{

recurse;

}

recurse;


第二種是精巧模式,它包含兩個函數:


function first{

second;

}

function second{

first;

}

first;


在這種遞歸模式中,兩個函數互相調用對方,形成一個無限循環。大多數調用棧錯誤與這兩種模式有關。常見的棧溢出原因是一個不正確的終止條件,因此定位模式錯誤的第一步是驗證終止條件。如果終止條件是正確的,那麼算法包含了太多層遞歸,為了能夠安全地在瀏覽器中運行,應改用迭代、製表或混合模式。