Struggling with variable assignment in a nested function

I’m having an issue assigning a variable declared in an outer function inside a nested function. I think it might be an async or hoisting issue but I can’t figure it out. I did some testing and that is working like I’d expect and I can’t see where the difference is between my working test and my not working app.

You can see in this pen that the variable level is declared in the outer most function first() and logged from that function, but it’s overridden by the innermost function third() and the log correctly displays “third”.

However in my weather app the msg variable isn’t being assigned the same way even though the nesting appears to be identical. The only difference I can discern has to do with the async API call, which may be way the console.log shows the unchanged version.

Any help explaining what’s going on and how I can test/view the difference better myself is tremendously appreciated.

i am pretty sure that you need to declare the global variable in the global scope by moving the declaration outside the entire function.

like this:

var level = "";

function first() 
{
    level = "first";

    function second() 
    {
        level = "second";

        function third() 
        {
            level = "third";
        }
        third();
    }
    second();

    console.log(level);
}

first();
1 Like

I second JuggernOtt81’s response. You cannot access the local variable that was declared in the first() function in another function. You would need to declare the variable in the global scope that way it can be accessed globally.

It is because msg is being changed inside an asynchronous function, but you are printing it to the screen before the async function has fetched the data from your api. In other words, you are printing msg (via console.log()) synchronously but setting it’s value asynchronously in .getJSON, and the synchronous is executed first as the async is not done yet.
Here is a simple test, set a boolean flag to false in the top of the function and then set it to true inside your getJSON, i.e. after the data comes back , now console.log() msg only if the flag is true at the same place you are printing now, you will see that it never executes because the flag only turns true inside the async function.
It has nothing to do with your declaration or hoisting, you got that part fine.

1 Like

Well I was almost on the right track then. :smiley:

Can you recommend any place to read/learn about good function architecture or specifically, avoiding callback hell? Because it seems like all of the DOM manipulating functions have to go inside the callback so they get called once there is data to put in them. Or is this what event listeners are for? Like… go run this function, then run this function only when there is a response?

Well, I really don’t want to confuse you as I don’t know where you are in your coding journey, but this subject can be a very confusing (but at the same time an extremely important) aspect of JavaScript. My first advise would just be to go through all the projects in the order given and by the time you get to the back-end projects you will get a firmer understanding.

But while you are doing so, read about the Event loop/ call stack when you get a chance, to get a firmer understanding how async (and sync) functions are handled / executed in javascript, here is one basic article (but really you can find many articles with google if you key in the above terms)
https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40

To make it more practical with your current case, consider changing your console.log(msg) statement at the end of your showMeTheWeather() function to the following:

setTimeout(()=>{
    console.log(msg)
  },1000)

You will see that the message returned from the api will be printed, this is because the statement is executed after 1000 ms (if you haven’t used it before, read about the basic usage of setTimeout here), now change the timeout parameter to 1ms, and see that nothing gets printed, why? because 1ms is not long enough for the message to have been retrieved from the api.
By introducing the setTimeout function we have basically added a new event to the event table, which sends it to the event queue and via the event loop it is added to the call stack (once it is empty) .
I hope I haven’t confused you further, but the more practical projects you do the more it will make sense.

1 Like

That’s really excellent. Thanks so much!