Help - Search - Members - Calendar
Full Version: Variable Scope
Christian Webmasters Forums > Web Design Help Forums > Web Development > HTML / CSS / Javascript / DOM
hunter121
I have this piece of code that I derived from w3schools.com's AJAX tutorial, it uses a function pointer for the action for onreadystatechange, as you can see:
CODE
function ajax(param) {
            var xmlHttp;
            var retval = null;
            try {
                xmlHttp = new XMLHttpRequest();
            } catch (e) {
                alert("Browser does not support AJAX.");
                return;
            }
            xmlHttp.onreadystatechange = function() {
                if(xmlHttp.readyState==4) {
                    retval = xmlHttp.responseText;
                }
            };
            xmlHttp.open("GET",("response3.php?action="+param),true);
            xmlHttp.send(null);
                        return retval;
        }

However, retval is out of scope in the function pointer. In other words, the line of code " retval = xmlHttp.responseText; " is creating a new variable called retval in a new scope that has absolutely nothing to do with the "retval" declared at the beginning of the ajax() function. So my question is, how do I refer to the retval in the super scope? I want to make my code reusable instead of having to define unique ajax() functions that display their responseText by changing the innerHTML of different HTML elements.

If you have a better way of AJAX-ing than my code, please suggest it because I really hate using function pointers in this case
Thanks.
JAAulde
Dustin has something about this on his site somewhere, but what you are looking for is scope adjustment via call() and apply().

Jim
bobbymac
QUOTE(hunter121 @ Aug 31 2007, 07:19 AM) *
However, retval is out of scope in the function pointer. In other words, the line of code " retval = xmlHttp.responseText; " is creating a new variable called retval in a new scope that has absolutely nothing to do with the "retval" declared at the beginning of the ajax() function.


It's been a little while since I have done any JS coding, but I am pretty certain that in this case, retval IS actually read from the outer scope (i.e. the function body of ajax() ). In fact, if you didn't precede retval with "var" in the ajax() function body, then the function would be referring to the global variable retval. JavaScript is the opposite to PHP in this regard: in JS, variables are global by default, unless you explicitly declare them as local to the function body by preceding the first use of them with "var".

Are you having problems with this code, or are you simply trying to understand how it works? AJAX is trickier than a lot of other JavaScript because it is Asynchronous
JAAulde
Paul is right in that you could make retval a global variable and it would be accessible from within the called function. The problems with the "AJAX" style of event subscription is when you try to do proper OOP programming by getting all your ariables out of the global namespace. There are also problems when you need to send arguments to the function your are subscribing to onreadystatechange. All of these issues are solvable with call() and apply().
bobbymac
Well, the problem of global variables is muted somewhat in this case because the retval variable is local to the ajax function body.

What I was trying to say was, retval is accessible from within the called (anonymous) function, contrary to what was stated by Hunter.
JAAulde
QUOTE(bobbymac @ Sep 4 2007, 11:06 AM) *
What I was trying to say was, retval is accessible from within the called (anonymous) function, contrary to what was stated by Hunter.
I am not so sure about it either way at this moment...though I am inclined to think that it isn't accessible. I believe that because retval is declared in the scope of the function, ajax(), it will not be available within the scope of the function that is subscribed to onreadystatechange. It would take some testing to prove it at this point and I don't have time for that, but I remember my initial frustrations in trying to use proper patterns with AJAX and how blown away I was when I saw Dustin talking about call() and apply().

I finally dug up that article, by the way... http://www.dustindiaz.com/javascript-scope-adjustment It is long and doesn't get to call() and apply() until further down as it was an after thought for him.
bobbymac
Give this test code a whirl:
CODE

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>Untitled</title>
</head>

<body>
<div id="testdiv" style="height: 100px; width: 100px; background-color: #FF0000;">click here</div>
<script type="text/javascript">
<!--
function test(action) {
var testdiv = document.getElementById('testdiv');
var teststr = 'aaa';
var testobj = {a:'hello',b:'there'};
testdiv.onclick = function (a) {
alert(teststr);
teststr = 1;
alert(testobj.a);
alert(testobj.cool.gif;
testobj.a += 'my name is';
testobj.b += 'Paul';
}
document.onkeypress = function () {
alert(testobj.a + testobj.cool.gif;
alert(action);
action(testobj.a + testobj.cool.gif;
}
return teststr;
}
var myfunc = function(str) {
var testdiv = document.getElementById('testdiv');
var newtxt = document.createTextNode(str);
testdiv.appendChild(newtxt);
}
alert(test(myfunc));

// -->
</script>


</body>
</html>

(sorry for the dirty coding tongue.gif)
By clicking in the red square, you will see that the inner event handler function does indeed have access to the outer teststr variable - it displays this in the alert. However, since the event occurs after the function test() returns, it makes no difference to the return value. Each time test() is run, it starts over, declaring teststr and the event handler. But when you click the red box, teststr (and testobj) are set/altered. And when you press a key, you see the current contents of testobj appended in the red div.

So the problem with the code above is the timing, not the scope. The ajax function returns immediately (an empty string), meanwhile the xmlhhtp request takes place (asynchronously), changes the retval variable, but of course it is too late - the ajax function has already returned. In my test code, you can pass in a function as an argument, which gets called when a certain event occurs. In this case, it is keypress, but it could just as well be the onreadstatechange event of the xmlhtttprequest object. That way, you can make something happen when it has finished loading the asynchronous request.
JAAulde
Ahh, yes, the timing causes the variable to get blown away making it seem out of scope. Very nice, Paul.

Jim
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.