2008-11-09 73 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)); 
    });