2

I'm just starting out learning javascript, and tried to write a little script that would make a grid of divs on a page.

Here's the script:

var tileWidth=50;
var tileHeight=100;
var leftPos=10;
var topPos=10;
var columns=10;
var rows=10;
var spacing=5;

$('document').ready(function() {
 placeTiles();
});

function makeRow() {
 for (var i=0; i<columns; i++) {
   $('#canvas').append('<div class="tile" style="left:' + leftPos + 'px;top:' + topPos + 'px;"></div>');
   var leftPos = leftPos + tileWidth + spacing;
 }
}

function placeTiles() {
 for (var i=0; i<rows; i++) {
  makeRow();
  var topPos = topPos + tileHeight + spacing;
 }
}

At the moment, 100 <div>s get created, all with a top position of 10px and a left position of undefined (for the first <div> in the row) or NaN.

What should I be doing differently? Why can't makerow() see my global leftPos variable (and all the other variables for that matter)?

Thanks.

2
  • dont use var in front of leftPos, because you have declared left post at the top of your script Commented Apr 24, 2010 at 22:55
  • leftPos sorry, in your foreach remove var from "var leftPos" Commented Apr 24, 2010 at 22:55

3 Answers 3

3

"Why can't makerow() see my global leftPos variable (and all the other variables for that matter)?"

Because var is not a declaration. It is a function(scope)-wide annotation. In the top-level scope var essentially does nothing (the global execution context/scope is the window object) so it is the same as window.leftPos = 10 or just leftPos = 10. In the makeRow you essentially have:

function makeRow() {
 var leftPos = undefined // this is "hoisted" to the TOP of the function
 for (...) {
  // ...
  leftPos = leftPos + tileWidth + spacing
 }
}

Something look suspicious? :-)

Two solutions to this are 1) use a different variable name (recommended) 2) use the 'global' leftPos a property of the window object (as shown below).

Also, even though it is just a scope-wide annotation, it generally leads to more clear code if you keep the 'var's at the top (it is "hoisted" anyway, see above). Eg:

function makeRow() {
 var leftPos = window.leftPos // or use a different name, which is what I'd do
 for (var i=0; i<columns; i++) {
   $('#canvas').append('<div class="tile" style="left:' + leftPos + 'px;top:' + topPos + 'px;"></div>')
   leftPos = leftPos + tileWidth + spacing
 }
}

For more information, see: Identifier Resolution, Execution Contexts and Scope Chains

Sign up to request clarification or add additional context in comments.

3 Comments

Oh I think I see! When I do var leftPos = leftPos + tileWidth + spacing, I'm declaring a local variable leftPos, which overrides the global variable with the same name (actually what I wanted), but then when I try to assign the global variable to it, it has already been overwritten! So I can either refer to the global variable with the alternative method of window.leftPos, or give the global variable a different name. Thanks!
@Acorn: Overwritten may not be the right term. The global variable would still exist, but since you had another local variable with the same name, the global one would not be accessible, unless you use window.leftPost.
Shadowed is the term I believe.
1

you declare leftPos to be of function scope with var leftPos, hiding the global declaration. If you're not declaring something don't use var

1 Comment

But I'd already declared leftPos as a gloval var at the beginning of the script. I thought that I could then assign a local var with the same name within the function so that it would take the global var, add the other variables to it, and then overwrite it, so that all the other loops in the function would use the local var instead of the global. Then the next time the function was called it would reset back to the global var. So I can't do that?
1

In JavaScript you can have function scope or global scope for your variables.

If you have two variables of the same name in different scopes, the first preference is given the variable declared in the function scope.

Therefore you have your leftPos and topPos variables declared in global scope at the top of the script, and you also have them declared within the makeRow() and placeTiles() functions. The var keyword is used for variable declaration, not for variable assignment.

You simply need to remove the variable declaration with var from within the functions, in order to use the global variables. Simply use:

leftPos = leftPos + tileWidth + spacing;

// and

topPos = topPos + tileHeight + spacing;

However, you should consider avoiding global variables altogether. Globals are evil.

Further reading:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.