69

I have a function that is set up as follows

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

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

To my logic, that alert should return 'foo', but instead it returns undefined. What am I doing wrong?

UPDATE: Here's my actual code (it's a function for reverse-geocoding with the Google API)

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;
    });   
   }
2
  • 4
    I recommend reading about how Javascript Closures work: jibbering.com/faq/faq_notes/closures.html#clClose Commented Apr 10, 2010 at 2:23
  • If you're having the issue where, perhaps the nested function is an event of sorts and thus you can't receive the return value of the nested value. I'd suggest using Promises. I'd love to make an answer to this question with code block examples of how to use Promise in this case but I can't because it's "answered". Commented Oct 27, 2023 at 21:06

3 Answers 3

68

you have to call a function before it can return anything.

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

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

Or:

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

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

for your actual code. The return should be outside, in the main function. The callback is called somewhere inside the getLocations method and hence its return value is not recieved inside your main function.

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
   }
Sign up to request clarification or add additional context in comments.

5 Comments

I've updated my question with the actual code. The problem I have is that I'm working with the Google API and so my sub-function is being called by one of their functions. Any ideas how I would get around it?
Thanks. The problem there is that when I simply put return country; it returns " ", because I usually haven't received the info back from Google quick enough. Is there a way of getting it to wait until the value changes?
@chris i think the better way to use these APIs is to put your logic (the stuff that you'd like to do with the country, address ..) inside the callback.
you've missed my favorite alternative return (funtion(){...})();
getLocations is asynchronous. That code can't work.
3

Right. The function you pass to getLocations() won't get called until the data is available, so returning "country" before it's been set isn't going to help you.

The way you need to do this is to have the function that you pass to geocoder.getLocations() actually do whatever it is you wanted done with the returned values.

Something like this:

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
  }
}

If you might want to do something different every time you get the location, then pass the function as an additional parameter to 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);

If this looks a little messy, then you could take a look at something like the Deferred feature in Dojo, which makes the chaining between functions a little clearer.

2 Comments

Thanks, the problem I have however is that I'm wanting to use the reverseGeocode several times throughout my code. I have a list of status updates and their locations returned from the twitter API, and so am wanting to call reverseGeocode for each one. Also, I'm wanting to call reverseGeocode for the current user's location. Not sure if that makes sense... the site is at chris-armstrong.com/whispers if you want to take a look and see what I mean
When in doubt, use more functions:-) See edits above...
3

Just FYI, Geocoder is asynchronous so the accepted answer while logical doesn't really work in this instance. I would prefer to have an outside object that acts as your 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);
                }
        }
    });
};

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.