homepage Welcome to WebmasterWorld Guest from 54.166.53.169
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
Forum Library, Charter, Moderator: open

JavaScript and AJAX Forum

    
scope
function call within code block not recognizing global var
nyteshade



 
Msg#: 4418326 posted 1:28 pm on Feb 16, 2012 (gmt 0)

I am testing the workings of function array-like object arguments array. In an html file I have:

js_functions.html

<div id="args"></div>
<script ...core.js"></script>
<script ...js_functions.js"></script>


I show this so that you may see that the core.js is loaded first.

core.js

function write_results(){
var d = document;
myp = d.createElement("p");
myp.appendChild(mytn);
myid.appendChild(myp); <<<ERROR GEN HERE
}


Next:

js_functions.js

function jsfunctions_args(){
var d = document;

//function call with arguments
displayProjects("Bluebeam", "Artichoke", "Monarch", "Starfish", "PaperClip", "Naomi", "Butterfly");

myid = d.getElementById("args");

function displayProjects(){
for(var i = 0; i < displayProjects.arguments.length; i++){
//placed here the myid = ... works?
mytn = d.createTextNode(displayProjects.arguments[i]);
write_results();
}
}
}


The way the code is structured above will generate an error when myid is parsed indicated above <<<ERROR GEN HERE.

However, when I place the line
myid = d.getElementById("args"); within the 'for code block' then the routine works but I was trying to avoid making multiple, what I considered unnecessary, references.

My questions: why is the global myid failing with 'myid is undefined'? I assume that since it is a global variable and its value/state remains unaltered that it may be referenced from anywhere in the current document?

The for block is not blind to global var statements... or is the
write_results function ignoring global variables since it is nested within a function? I'm guessing, that's why I'm here, arrgh! Thanks all.

 

nyteshade



 
Msg#: 4418326 posted 9:57 am on Feb 17, 2012 (gmt 0)

Well, I've been at Mozilla Developers Network reading up on functions and it appears that I've stumbled over a closure.


You can nest a function within a function. The nested (inner) function is private to its containing (outer) function. It also forms a closure.

A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression). [1]

Since a nested function is a closure, this means that a nested function can "inherit" the arguments and variables of its containing function. In other words, the inner function contains the scope of the outer function.

To summarize:

The inner function can be accessed only from statements in the outer function.

The inner function forms a closure: the inner function can use the arguments and variables of the outer function, while the outer function cannot use the arguments and variables of the inner function.



So, simply placing the offending line within the inner function works:


function displayProjects(){
myid = d.getElementById("args");
for(var i = 0; i < displayProjects.arguments.length; i++){
mytn = d.createTextNode(displayProjects.arguments[i]);
write_results();
}
}


But I still do see why the outer function scope containing a global variable is not able to be referenced by the for block within the closure? Maybe it's the write_results() causing the problem; no, that's not it because even if I replace write_results() with alert(), the alert never gets a chance to execute.

blend27

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4418326 posted 10:37 am on Feb 17, 2012 (gmt 0)

myp.appendChild(mytn);

mytn is passed, but does not exist yet. so appendChild() says who is mytn?

Fotiman

WebmasterWorld Senior Member fotiman us a WebmasterWorld Top Contributor of All Time 5+ Year Member



 
Msg#: 4418326 posted 2:57 pm on Feb 17, 2012 (gmt 0)

The problem is that you are setting myid AFTER the call to displayProjects. Therefore, when displayProjects is executed, myid is still undefined. This will work:


function jsfunctions_args(){
var d = document;
// set myid BEFORE calling displayProjects
myid = d.getElementById("args");

//function call with arguments
displayProjects("Bluebeam", "Artichoke", "Monarch", "Starfish", "PaperClip", "Naomi", "Butterfly");

function displayProjects(){
for(var i = 0; i < displayProjects.arguments.length; i++){
mytn = d.createTextNode(displayProjects.arguments[i]);
write_results();
}
}
}


With that said, this approach is not really a very good approach. You have a bunch of global variables being created, and it's not easy to debug where each is getting set (as you've found). It's also a good practice to declare every variable using "var", so you know where the scope is. Also, your function definition appears in the file below the call to the function. That call happens from inside another function which is called externally (after the entire script has loaded), so it will work, but I generally prefer to put the definitions first in the file so that it's easier to find them, but also if you ever need to call that function from within that file before the entire script has been processed, then you'll need it to be defined first.

I think there's a lot of room for improvement in this script.

nyteshade



 
Msg#: 4418326 posted 6:07 pm on Feb 17, 2012 (gmt 0)

fotiman: exactly what I needed to hear. I was getting a nagging feeling (a headache) over my use of global variables. I've read nearly all of what you said at MDN over the last day so, thanks for taking the time to confirm. I have to make these kind of bone-head errors from time to time, part of how I learn things. Peace.

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved