函數|技巧
function funcA(){
funcB();
//other code
}
怎麼定義函數B,讓B在啟動並執行時候不僅能終止B本身,而且能終止函數A的運行?
這是個非常規的問題,我們分兩大部分討論. (1.為什麼一定這樣做 2.怎麼實現)
1. 顯然,這種編碼方式已經打亂了正規的程式編寫原則,我們編寫函數的目的就是為了封裝,為了實現代碼的模組化. 如果B能讓A退出返回, 那這種編碼方式肯怕比濫用 goto 語句還濫了.
這樣做有必要嗎?為什麼一定要這樣做....??
答案如下:
假如我們要擴充Array的prototype. 比方說:定義一個 find方法,用來返回第一個讓 執行函數為真的數組元素.
1 <script>
2 // by go_rush(阿舜) @ http://ashun.cnblogs.com
3
4 Array.prototype.each=function(f){
5 for(var i=0;i<this.length;i++) f(this[i],i,this)
6 }
7
8 Array.prototype.find=function(f){
9 var result;
10 this.each(function(value,index,arr){
11 if (f(value,index,arr)) result=value
12 })
13 return result
14 }
15
16 var arr=[1,2,3,4,5,7,9]
17
18 function foo(v){ //檢測是不是偶數
19 return v%2==0
20 }
21 alert(arr.find(foo))
22
23 </script>
結果另我們大失所望.
首先: 在邏輯上,程式是錯誤的,因為我們期望返回第一個偶數,但是程式卻返回的是最後一個偶數.
其次: 程式的效率是低下的,那怕是找最後一個偶數,他在找到偶數4後,仍然檢測了4後面的所有元素.這個動作
是多餘的.
怎麼辦呢? 請看代碼中的第11行,如果檢測到 f(value,index,arr) 為真的時候,能夠直接中斷函數 this.each()該多好啊. 效率,結果,雙贏的局面.
所以對於問題一 "為什麼一定這樣做" , 在這裡,具體到這個應用上,有足夠的理由讓函數 B()來中斷函數A()
看到這裡,你可能會問: 你的 find 方法為什麼不這樣寫?
Array.prototype.find=function(f){
for(var i=0;i<this.length;i++){
if (f(this[i],i,this)) return this[i]
}
}
這樣不整個世界都清淨了嗎.
是的,如果我只是簡單的寫一個find 這樣寫肯定沒問題,但是如果現在我正在寫一個複雜的應用,或一個寫一個js架構呢
我要實現一系列的
Array.prototype.all
Array.prototype.any
Array.prototype.each
Array.prototype.map
Array.prototype.find
Array.prototype.findAll
Array.prototype.grep
Array.prototype.inject
...... 詳細請參見 prototype.js v1.4 有上十種方法等著實現呢,我怎不可能每個方法都用 for迴圈一個一個的
遍曆數組把. 我肯定要實現一個 each 方法作為統一入口吧.
閑話少說,我們來看怎麼解決問題:
要在 B函數中終止A函數,並返回結果, 目前我能想到的辦法就是用異常 try{}catch(x){}
實現代碼
1 <script>
2 // by go_rush(阿舜) @ http://ashun.cnblogs.com
3
4 var $break=new Object()
5
6 Array.prototype.each=function(f){
7 try{
8 for(var i=0;i<this.length;i++){
9 try{
10 f(this[i],i,this)
11 }catch(e){
12 if (e==$break) throw e
13 }
14 }
15 }catch(e){
16 }
17 }
18
19 Array.prototype.find=function(f){
20 var result;
21 this.each(function(value,index,arr){
22 if (f(value,index,arr)){
23 result=value
24 throw $break
25 }
26 })
27 return result
28 }
29
30 var arr=[1,2,3,4,5,7,9]
31
32 function foo(v){ //檢測是不是偶數
33 return v%2==0
34 }
35 alert(arr.find(foo))
36
37 </script>
在第24行,如果程式已經找到第一個滿足函數傳回值為真的元素,那麼就拋出一個自訂異常,終止 this.each()的
運行.. 注意第12行,只有確保函數拋出的是自訂異常才繼續向上拋出異常,從而終止函數的運行.
在上面的代碼中,我用的 try---catch方法完全是用來解決本貼所提出的問題的,並未進行任何其他錯誤處理.
在這方面,prototype.js ,通過定義兩個自訂異常對象 $break 和 $continue ,既照顧到了異常處理,又解決了本貼
提出的問題. Enumerable 對象實現得很優雅, 大家不妨再去體會體會 prototype.js 中Enumerable的妙處.
我們看看prototype.js 是怎麼做的,我還是貼出來把
prototype.js的程式碼片段摘取
var $break = new Object();
var $continue = new Object();
var Enumerable = {
each: function(iterator) {
var index = 0;
try {
this._each(function(value) {
try {
iterator(value, index++);
} catch (e) {
if (e != $continue) throw e;
}
});
} catch (e) {
if (e != $break) throw e;
}
},
all: function(iterator) {
var result = true;
this.each(function(value, index) {
result = result && !!(iterator || Prototype.K)(value, index);
if (!result) throw $break;
});
return result;
},
any: function(iterator) {
var result = true;
this.each(function(value, index) {
if (result = !!(iterator || Prototype.K)(value, index))
throw $break;
});
return result;
},
http://www.cnblogs.com/ashun/archive/2006/11/29/function_call_prototype_break_continue_gorush.html