I am having a problem with what I assume is understanding variable scope in Javascript. I thought I had a good grasp on this topic. I am working on the random quote generator. I am attempting to use JSON data from an api I found. (Using an array of strings seemed too straightforward to me, so I wanted to tackle the challenge with something I didn’t understand).
At this point I am simply trying to alter a variable ‘test’ within my $.getJSON function, but it keeps returning undefined.
var test;
$.getJSON("http://quotes.stormconsultancy.co.uk/random.json", function(json) {
$("#test1").html("<p> " + json.quote + "</p>");
test = json.quote;
});
$("#test2").html("<p> " + test + "</p>");
Why doesn’t my test variable show any change from the function? Even if I change it from test = json.quote;
to test = "blah";
I see no change outside the scope of the function. I feel like I am missing something obvious.
Thanks for any help.
Note: If you want to see this with the JSON data loaded, you have to click up to the left of the url in your browser and disable https, as the api sends http data, and firefox at the least won’t allow mixed media. I assume this is true for other browsers as well…
@stephanpssantos, thanks, that information about the problems that arise with the fact that ajax is asynchronous is definitely something good to know about!
@vickylaiio, blow away on your own horn, that article about closure is definitely helpful for this. I feel like I’m getting a little more clarity from reading it, but I’ve also been sitting here a while today, I’ll check it out tomorrow with a fresh mind and probably get even more from it. Thanks!
I am still having a hard time understanding why I can globally access a variable in a function like this:
var test = 0;
function myfunction() {
test ++;
};
myfunction();
$("#test2").html("<p> " + test + "</p>");
but once that variable is in this (a function nested in a function?) :
var test = 0;
function myfunction() {
$.getJSON("http://quotes.stormconsultancy.co.uk/random.json", function(json) {
$("#test1").html("<p> " + json.quote + "</p>");
test ++;
});
};
myfunction();
$("#test2").html("<p> " + test + "</p>");
The change is no longer in the global variable.
How would I show the change test++ globally outside the scope of the functions if I wanted for some reason to use test++ inside that function?
From what I can see, you have decent understanding of scopes in javascript. Don’t even worry about that.
The thing you’re not really understanding here is the asynchronous nature of javascript.
As you may already know $.getJSON is just a highly specific version of $.ajax. And $.ajax is just an abstraction of XMLHttpRequest. So by nature, all these APIs are asynchronous (referred to as async henceforth)
What async actually means is that when you make an async call (like an ajax call), the data will be available sometime later in future. It is not blocking. In simpler words, when you trigger an async call, your program will NOT wait till that operation is complete. It will immediately proceed further and execute whatever comes next.
So in your code snippet, the order in which your statements are executed is as follows
Line 1
Line 3
Line 8 (since you're making an ajax request on line 3)
Line 4
Line 5
It will not happen sequentially.
Therefore, your #test2 will show undefined. Since, the lines 4 and 5 will be executed later on when the $.getJSON succeeds.
If you want to make your code execution order more expressive, you may want to take a look at this post I made not very long ago.
Waking up with a clear head this morning was definitely helpful. I made a quick pen to demonstrate that the problem was with my use of ajax without regard to its asynchronous nature.
Here, I have not changed the scope of the variable “test” at all. But I have created two buttons: “click” simply performs the function including $getJSON which changes the #test1 div to the json.quote data. Then I can wait a few moments ensuring everything is complete, press “click2” to see the updated #test2 html using the “test” variable. No variable scope change, and now can see that the function did update “test” with the JSON data.
I feel like this is kind of a convoluted explanation, as there are some great, clear articles on asynchronicity out there. But I was pretty unsure to if I was misunderstanding scope or if it was a different problem, but got some helpful input here from everyone.