2010-04-10 20 views
44

J'ai une fonction qui est définie comme suitValeur de retour de la fonction Javascript nichée dans

function mainFunction() { 
     function subFunction() { 
      var str = "foo"; 
      return str; 
     } 
} 

var test = mainFunction(); 
alert(test); 

Pour ma logique, cette alerte doit retourner « foo », mais il renvoie undefined. Qu'est-ce que je fais mal?

MISE À JOUR: Voici mon code actuel (il est une fonction inverse géocodage avec l'API Google)

function reverseGeocode(latitude,longitude){ 
    var address = ""; 
    var country = ""; 
    var countrycode = ""; 
    var locality = ""; 

    var geocoder = new GClientGeocoder(); 
    var latlng = new GLatLng(latitude, longitude); 

    return geocoder.getLocations(latlng, function(addresses) { 
    address = addresses.Placemark[0].address; 
    country = addresses.Placemark[0].AddressDetails.Country.CountryName; 
    countrycode = addresses.Placemark[0].AddressDetails.Country.CountryNameCode; 
    locality = addresses.Placemark[0].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName; 
    return country; 
    }); 
    } 
+4

Je recommande la lecture sur la façon dont le travail Javascript Closures: http://jibbering.com/faq/faq_notes/closures.html#clClose – Bartek

Répondre

54

vous devez appeler une fonction avant de pouvoir retourner quoi que ce soit.

function mainFunction() { 
     function subFunction() { 
      var str = "foo"; 
      return str; 
     } 
     return subFunction(); 
} 

var test = mainFunction(); 
alert(test); 

Ou:

function mainFunction() { 
     function subFunction() { 
      var str = "foo"; 
      return str; 
     } 
     return subFunction; 
} 

var test = mainFunction(); 
alert(test()); 

pour votre code actuel. Le retour devrait être à l'extérieur, dans la fonction principale. Le rappel est appelé quelque part dans la méthode getLocations et sa valeur de retour n'est donc pas reçue dans votre fonction principale.

function reverseGeocode(latitude,longitude){ 
    var address = ""; 
    var country = ""; 
    var countrycode = ""; 
    var locality = ""; 

    var geocoder = new GClientGeocoder(); 
    var latlng = new GLatLng(latitude, longitude); 

    geocoder.getLocations(latlng, function(addresses) { 
    address = addresses.Placemark[0].address; 
    country = addresses.Placemark[0].AddressDetails.Country.CountryName; 
    countrycode = addresses.Placemark[0].AddressDetails.Country.CountryNameCode; 
    locality = addresses.Placemark[0].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName; 
    }); 
    return country 
    } 
+0

J'ai mis à jour ma question avec le code actuel. Le problème que j'ai est que je travaille avec l'API Google et donc ma sous-fonction est appelée par l'une de leurs fonctions. Des idées comment je le contournerais? –

+0

Merci. Le problème, c'est que quand je mets simplement le pays de retour; il renvoie "", car je n'ai généralement pas reçu les informations de Google assez rapidement. Y at-il un moyen de l'attendre jusqu'à ce que la valeur change? –

+1

@chris Je pense que la meilleure façon d'utiliser ces API est de mettre votre logique (les choses que vous aimeriez faire avec le pays, l'adresse ..) dans le rappel. – z33m

3

Droite. La fonction que vous passez à getLocations() ne sera pas appelée tant que les données ne seront pas disponibles. Par conséquent, renvoyer "country" avant d'avoir été défini ne vous aidera pas.

La façon dont vous devez faire cela est de faire en sorte que la fonction que vous transmettez à geocoder.getLocations() fasse ce que vous voulez avec les valeurs retournées.

Quelque chose comme ceci:

function reverseGeocode(latitude,longitude){ 
    var geocoder = new GClientGeocoder(); 
    var latlng = new GLatLng(latitude, longitude); 

    geocoder.getLocations(latlng, function(addresses) { 
    var address = addresses.Placemark[0].address; 
    var country = addresses.Placemark[0].AddressDetails.Country.CountryName; 
    var countrycode = addresses.Placemark[0].AddressDetails.Country.CountryNameCode; 
    var locality = addresses.Placemark[0].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName; 
    do_something_with_address(address, country, countrycode, locality); 
    }); 
} 

function do_something_with_address(address, country, countrycode, locality) { 
    if (country==="USA") { 
    alert("USA A-OK!"); // or whatever 
    } 
} 

Si vous pouvez faire quelque chose de différent chaque fois que vous obtenez l'emplacement, passez ensuite la fonction en tant que paramètre supplémentaire à reverseGeocode:

function reverseGeocode(latitude,longitude, callback){ 
    // Function contents the same as above, then 
    callback(address, country, countrycode, locality); 
} 
reverseGeocode(latitude, longitude, do_something_with_address); 

Si cela semble un peu compliqué, alors vous pourriez jeter un oeil à quelque chose comme la fonction différée dans Dojo, ce qui rend le chaînage entre les fonctions un peu plus clair.

+0

Merci, le problème c'est que je veux utiliser reverseGeocode plusieurs fois dans mon code. J'ai une liste de mises à jour de statut et leurs emplacements retournés de l'API de twitter, et donc je veux appeler reverseGeocode pour chacun. En outre, je veux appeler reverseGeocode pour l'emplacement de l'utilisateur actuel. Pas sûr si cela a du sens ... le site est à http://www.chris-armstrong.com/whispers si vous voulez jeter un oeil et voir ce que je veux dire –

+0

En cas de doute, utilisez plus de fonctions: -) Voir les modifications ci-dessus ... –

1

Juste pour info, Geocoder est asynchrone donc la réponse acceptée tout en logique ne fonctionne pas vraiment dans ce cas. Je préférerais avoir un objet extérieur qui agit comme votre updater.

var updater = {}; 

function geoCodeCity(goocoord) { 
    var geocoder = new google.maps.Geocoder(); 
    geocoder.geocode({ 
     'latLng': goocoord 
    }, function(results, status) { 
     if (status == google.maps.GeocoderStatus.OK) { 
      updater.currentLocation = results[1].formatted_address; 
     } else { 
      if (status == "ERROR") { 
        console.log(status); 
       } 
     } 
    }); 
};