2008-11-09 104 views
15

這是一個棘手的問題,因爲代碼完全正常工作,它只是激發了我的審美意識,有點微不足道。我正在轉向堆棧溢出,因爲我的大腦現在正在讓我失望。Javascript回調函數和遞歸

下面是使用Google Maps JS API查找地址並在地圖上放置標記的代碼片段。但是,有時最初的查找失敗,所以我想用不同的地址重複該過程。

geocoder.getLatLng(item.mapstring, function(point) { 
    if (!point) { 
     geocoder.getLatLng(item.backup_mapstring, function(point) { 
      if (!point) return; 
      map.setCenter(point, 13); 
      map.setZoom(7); 
      map.addOverlay(new GMarker(point)); 
     }) 
     return; 
    } 
    map.setCenter(point, 13); 
    map.setZoom(7); 
    map.addOverlay(new GMarker(point)); 
}) 

(至getLatLng第二個參數是一個回調函數。)

當然,你可以看到,該居中和縮放地圖,並添加標記的三條線是重複的,一旦在初級回調並在「回退回調」中一次(哈哈)。你可以找到一種方法來表達整個事情沒有任何冗餘?如果您的解決方案適用於任意數量的備份映射字符串,您就可以獲得獎勵積分和我的讚美。

回答

21

其他答案是好的,但這裏有一個選項。這可以讓你保持你開始用相同的形式,但使用的命名您lambda函數的伎倆,這樣你可以參考它遞歸:

mapstrings = ['mapstring1', 'mapstring2', 'mapstring3']; 

geocoder.getLatLng(mapstrings.shift(), function lambda(point) { 
    if(point) { 
     // success 
     map.setCenter(point, 13); 
     map.setZoom(7); 
     map.addOverlay(new GMarker(point)); 
    } 
    else if(mapstrings.length > 0) { 
     // Previous mapstring failed... try next mapstring 
     geocoder.getLatLng(mapstrings.shift(), lambda); 
    } 
    else { 
     // Take special action if no mapstring succeeds? 
    } 
}) 

的第一次使用符號「拉姆達」,它是將它作爲一個新的函數文字名稱來引入。第二次使用時,它是遞歸引用。

函數字面命名在Chrome中起作用,我假定它可以在大多數現代瀏覽器中使用,但是我沒有測試它,並且我不知道舊版瀏覽器。

+0

您不需要文字命名,您可以使用我在解決方案中使用的內容 - arguments.callee指向該函數。 – 2008-11-09 06:43:54

1

這個怎麼樣?

function place_point(mapstrings,idx) 
{ 
    if(idx>=mapstrings.length) return; 
    geocoder.getLatLng(mapstrings[idx], 
         function(point) 
         { 
          if(!point) 
          { 
           place_point(mapstrings,idx+1); 
           return; 
          } 
          map.setCenter(point, 13); 
          map.setZoom(7); 
          map.addOverlay(new GMarker(point)); 
         }); 
} 

儘可能多的備份字符串。第一次使用0作爲第二個參數。

2

是的,因素它變成一個功能:)

geocoder.getLatLng(item.mapstring, function(point) { 
    if (!point) { 
     geocoder.getLatLng(item.backup_mapstring, function(point) { 
       if (point) { 
        setPoint(point); 
       } 
     }) 
     return; 
    } 

    function setPoint(point) { 
     map.setCenter(point, 13); 
     map.setZoom(7); 
     map.addOverlay(new GMarker(point)); 
    } 

    setPoint(point); 
}); 
8

有在語言結構不明確支持遞歸執行遞歸一個非常不錯的方法稱爲不動點組合子。最爲人熟知的是Y-Combinator

Here is the Y combinator for a function of one parameter in Javascript

function Y(le, a) { 
    return function (f) { 
     return f(f); 
    }(function (f) { 
     return le(function (x) { 
      return f(f)(x); 
     }, a); 
    }); 
} 

這看起來有點嚇人,但你只需要編寫,一旦。使用它實際上很簡單。基本上,你把你的原始lambda的一個參數,並把它變成一個新的函數的兩個參數 - 第一個參數現在是實際的lambda表達式,你可以做遞歸調用,第二個參數是原始的第一個參數( point)你想要使用。

這就是你如何在你的例子中使用它。請注意,我使用mapstrings作爲查找字符串的列表,並且彈出功能會從頭開始破壞性地刪除元素。

geocoder.getLatLng(pop(mapstrings), Y(
    function(getLatLongCallback, point) 
    { 
    if (!point) 
    { 
     if (length(mapstrings) > 0) 
     geocoder.getLatLng(pop(mapstrings), getLatLongCallback); 
     return; 
    } 

    map.setCenter(point, 13); 
    map.setZoom(7); 
    map.addOverlay(new GMarker(point)); 
    });