Using var when declaring i in a for loop [duplicate] - javascript

This question already has answers here:
"var" or no "var" in JavaScript's "for-in" loop?
(10 answers)
Closed 7 years ago.
I've seen Javascript code that has used two different ways of defining a for loop.
for (var i=0;i < x.length; i++)
But it's also been
for (i=0; i < x.length; i++)
The same thing has happened with for-in loops
for (var i in x)
and
for (i in x)
Is there any difference between declaring i as a var and just saying i? Are there advantages of doing one over the other? Is one these right way to do this? From what I can tell, they both act the same, but there has to be some difference.
Note: I'm not asking about the difference between for-in and for (i=0)

Without a var declaration somewhere in a function, references to i will be to the i property of the global object. This risks all sorts of unpredictable behavior if code in the body of the for loop invokes code (say, inside a called method) that also modifies the global i.
Note that declaring var i in the for loop initialization
for (var i = ...)
is equivalent to declaring var i; before the for loop:
var i;
for (i = ...)
In particular, the declaration of i will be hoisted to the top of the enclosing scope.
EDIT: If you enable strict mode, then you must declare your loop variables (all variables, actually). Referencing a variable that has not been declared with a var statement will result in a ReferenceError being thrown (rather than resulting in a global variable coming into existence).

JavaScript is functionally scoped. At least for now, the language does not have block level variables.
When you write for (var i=0; ... ); it is the same as
var i;
for (i=0; ... );
In the absence of "use strict"; variable declaration will be hoisted.
for (i=0; ... ); alone implies that i belongs to the global (top most) object (in browsers it's window)

Intro:
The for statement creates a loop that consists of three optional
expressions
Source: Mozilla JavaScript Docs
Background:
You are referring to initialization, which is an expression or variable declaration. It's almost always used to initialize a counter variable that allows us to iterate through a collection as you've shown.
This expression may optionally declare new variables with the var
keyword. These variables are not local to the loop, i.e. they are in
the same scope the for loop is in. The result of this expression is
discarded.
In JavaScript, variables can hold different data types, and in the case of a counter variable, JavaScript treats the variable as a number.
Answer:
The reason one can optionally declare a new variable (or not at all, as you've highlighted) is due to the nature of the JavaScript programming language. You've hit upon an important aspect of the language that deals with variables and scope.
"To var or not to var"
Please see this other post about using var or not using it at all to understand more...
What is the function of the var keyword and when to use it (or omit it)?

If you say start using "i" without saying "var" first, you should have declared the variable before your for loop.
Like:
var i;
for (i = 0; i < x; i++) {
doSomething();
}
==OR==
for(var i = 0; i < x; i++){
doSomething();
}

Related

Mutating key inside JavaScript's for..in loop [duplicate]

What's the correct way to write a for-in loop in JavaScript? The browser doesn't issue a complaint about either of the two approaches I show here. First, there is this approach where the iteration variable x is explicitly declared:
for (var x in set) {
...
}
And alternatively this approach which reads more naturally but doesn't seem correct to me:
for (x in set) {
...
}
Use var, it reduces the scope of the variable otherwise the variable looks up to the nearest closure searching for a var statement. If it cannot find a var then it is global (if you are in a strict mode, using strict, global variables throw an error). This can lead to problems like the following.
function f (){
for (i=0; i<5; i++);
}
var i = 2;
f ();
alert (i); //i == 5. i should be 2
If you write var i in the for loop the alert shows 2.
JavaScript Scoping and Hoisting
The first version:
for (var x in set) {
...
}
declares a local variable called x. The second version:
for (x in set) {
...
}
does not.
If x is already a local variable (i.e. you have a var x; or var x = ...; somewhere earlier in your current scope (i.e. the current function)) then they will be equivalent. If x is not already a local variable, then using the second will implicitly declare a global variable x. Consider this code:
var obj1 = {hey: 10, there: 15};
var obj2 = {heli: 99, copter: 10};
function loop1() {
for (x in obj1) alert(x);
}
function loop2() {
for (x in obj2) {
loop1();
alert(x);
}
}
loop2();
you might expect this to alert hey, there, heli, hey, there, copter, but since the x is one and the same it will alert hey, there, there, hey, there, there. You don't want that! Use var x in your for loops.
To top it all off: if the for loop is in the global scope (i.e. not in a function), then the local scope (the scope x is declared in if you use var x) is the same as the global scope (the scope x is implicitly declared in if you use x without a var), so the two versions will be identical.
You really should declare local variables with var, always.
You also should not use "for ... in" loops unless you're absolutely sure that that's what you want to do. For iterating through real arrays (which is pretty common), you should always use a loop with a numeric index:
for (var i = 0; i < array.length; ++i) {
var element = array[i];
// ...
}
Iterating through a plain array with "for ... in" can have unexpected consequences, because your loop may pick up attributes of the array besides the numerically indexed ones.
edit — here in 2015 it's also fine to use .forEach() to iterate through an array:
array.forEach(function(arrayElement, index, array) {
// first parameter is an element of the array
// second parameter is the index of the element in the array
// third parameter is the array itself
...
});
The .forEach() method is present on the Array prototype from IE9 forward.
Actually, if you dislike declaration within for heading, you can do:
var x;
for (x in set) {
...
}
As mentioned in other answers to this question, not using var at all produces unnecessary side-effects like assigning a global property.
Use the one where you declare the loop variable with var. Implicitly declared variables have a different scope that's probably not what you intended.
for(var i = 0; ...)
is a commonly seen pattern but it's different from
for(int i; ...)
in C++ in that that the variable isn't scoped to the for block. In fact, the var gets hoisted to the top of the enclosing scope (function) so a local i will be effectively available both before the for loop (after the beginning of the current scope/function) and after it.
In other words, doing:
(function(){ //beginning of your current scope;
//...
for(var i in obj) { ... };
})();
is the same as:
(function(){ //beginning of your current scope;
var i;
//...
for(i in obj) { ... };
})();
ES6 has the let keyword (instead of var) to limit the scope to the for block.
Of course, you SHOULD be using local variables (ones declared with either var or let or const (in ES6)) rather than implicit globals.
for(i=0; ...) or for(i in ...) will fail if you use "use strict"; (as you should) and i isn't declared.
Using var is the cleanest way, but both work as described here: https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in
Basically, by using var you ensure that you create a new variable. Otherwise you might accidentally use a previously defined variable.
I think var is good for performance reasons.
Javascript won't look through the whole global scope to see if x already exists somewhere else.
From a general point of view, first version will be for an index that must live within loop's scope, while the other one would be any variable in the scope where loop's constructor got invoked.
If you're going to use loop's index inside for loop and this won't be required by others in next lines, better declare the variable with "var" so you'll be sure "x" is for loop's index initialized with 0, while the other one, if other "x" variable is available in this context, this will get overwritten by loop's index - that's you'll have some logical errors -.
I always use the block scoped let introduced in ES2015.
for (let x in set) {
...
}
Additional reading and examples

Javascript, is using the var keyword a best practice? [duplicate]

This question already has answers here:
What is the purpose of the var keyword and when should I use it (or omit it)?
(19 answers)
Closed 7 years ago.
It seems to me that anytime a variable is declared, it should use the var keyword (unless it's specifically trying to access a global variable). Particularly because local variables can be collected when their function exits. But does it make any difference in something like a for loop?
for(var i = 0; i < ...; i++)
Generally, is there any standard best practice about the use of var keyword?
Generally, is there any standard best practice about the use of var keyword?
Yes there is. And that is to use var every time.
But does it make any difference in something like a for loop?
There is no block-scope in javascript yet. So it makes no difference whatsoever. It is same as
var i;
for(i = 0; i < 10; i++) {
// you can access i inside
} // as well as outside the loop
Declaring variables without var keyword throws an error when used in 'use strict'. So it's always better to use var keyword and avoid the ambiguity by attaching a property to window if you want it to be global.
Ah forgot about let keyword, which will make its way in ES6, which allows for a block scope. So it can be written as
for(let i = 0; i < 10; i++){
// i can be accessed here but not outside this block
}
Also it's worth noting is that
MDN: First, strict mode makes it impossible to accidentally create global
variables. In normal JavaScript mistyping a variable in an assignment
creates a new property on the global object and continues to "work"
(although future failure is possible: likely, in modern JavaScript)
which means, that it is considered an accidental mistake if you omit var keyword and omitting it might not work in the future iterations of ECMAScript aka Javascript.
Use var and you'll not pollute global context, your variables will be context-aware and be fail-proof for future versions of javascript, or in MDN's words, modern JavaScript.
In Javascript, the var keyword appears to be optional. This is incorrect.
With var, a variable is created in the current scope. Without it, the variable is attached to the global scope. (This is window in the browser).
You should absolutely use var wherever possible. If you mean to intentionally attach a variable to the window, state that directly:
window.foobar = 'some text';
Declaring a variable in a for-loop is the same as declaring a variable anywhere else.
I doubt you want every loop in your program all trying to use window.i the same time, which is what will happen if you don't use var.
The comments are partially wrong.
Only functions have scope in javascript, so a for loop var has no actual functional difference. Using var in for loops does create the semantic implication that the value shouldn't be used later, though.
for(i = 0; i < 5; i++){}console.log(i);
for(var j = 0; j < 5; j++){}console.log(j);
q = 17
for(var q = 0; q < 5; q++){}console.log(q);
All 3 output 5 but with a var declaration I would not expect a future user of the for loop variable.

Why is a variable available outside it's code block? [duplicate]

This question already has answers here:
Why the for loop counter doesn't get destroyed after exiting the loop in javascript?
(3 answers)
Closed 9 years ago.
I ran into this little gem 5 minutes ago. I have been playing with JavaScript for a long while now and, since I follow best practice, I've never met such case, nor understand why it works while I supposed it shouldn't :
for (var i=0; i<10; i++){
// ... something
}
console.log("i=", i);
will output 10
How is i available outside the for block? I always thought the declaration part was to have a local variable only available within that block.
I always thought the declaration part was to have a local variable only available within that block.
Nope, not in JavaScript.
JavaScript loops (and most blocks in general) have no block scoping (until then next version rolls out with let.)
There are only two places where JavaScript does block scope at the moment and that's with clauses (you shouldn't use those anyway) and catch clauses.
Instead, JavaScript relies mostly on function scoping - variables declared in a function are local to that function.
In this case the declaration of i is outside the code block. In any case, Javascript doesn't have a block-level scope. Variables are either global, or within the scope of a function.
Because that's equivalent to:
var i=0;
while (i<10){
// ... something
i++;
}
In fact, loops do not even create their own scope at all:
var x = 0;
while (x < 10) {
x++;
var i = 5;
}
i; // 5
i will be available below where you have defined it, unless you close off the scope, like:
(function(){
for(var i=0; i<10; i++){
}
})();
console.log(i); // undefined
This should not matter though, because as long as you are using other loops below you can use the same increment variable (with the exception of nested loops), which will overwrite the other one. A problem could arise when you have a loop where you forget to use the keyword var. Always use var would be my recommendation. A closure is not usually necessary.
In a nested loop you can use the same increment variables again like:
for(var i=0; i<10; i++){
for(var n=2; n<44; n+=2){
}
}
// feel free to use `i` and `n` again
Or loops like this:
var ar1 = ['a', 'b', 'c'];
for(var i=0,l=ar1.length,n=0; i<l; i++,n+=2){
}
// feel free to use `i`, `l`, and `n` again
Personally, I find it a best practice to reserve vars i, n, c, and q for counters and l for length. Then I don't use them elsewhere, besides in loops.
In javascript, there's no "block scope", but "function scope". It means that, as soon as your variables are defined inside a function, they'll remain alive from the point that they're declared until the end of that function, whether inside or out side a block.
Here is the test case for js variable scope (from Secrets of the Javascript Ninja, sections 3.2.1 Scoping and functions)
Test case:
function outer(){
var a = 1;
function inner(){ /* does nothing */ }
var b = 2;
if (a == 1) {
var c = 3;
}
}
outer();
Result:

JavaScript loop variable scope

Just a quick question about the scoping of JavaScript variables.
Why does the alert() function print the value of i instead of returning undefined?
$(document).ready(function () {
for(var i = 0; i < 10; i += 1){
}
alert("What is 'i'? " + i);
});
I'm fairly new to JS, and in nearly all other languages I've dabbled, a declaration in the scope of the for loop would contain the value to that said loop, but not in this case, why?
i.e. What is 'i'? 10' is printed.
See the MDN for the "initialization parameters" of a for-loop:
An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
JavaScript didn't have block scope until const and let were introduced, just var which is function scoped. Since the initialization of i is within one function, that variable is accessible anywhere else in that same function.
From MDN:
Important: JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.
The javascript folks are trying to fix this!
EcmaScript6 (aka EcmaScript 2015) is the latest version of javascript that was passed last summer and browsers are just starting to support its features.
One of those features is block-scope local variables with the "let" expression. As of right now (April 2016), most of the current versions of the major browsers support this except Safari. Few mobile browsers support this.
You can read more about it here (in particular, see the section "let-scoped variables in for loops"):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
You can check current browser support here (look for the row Bindings -> let):
https://kangax.github.io/compat-table/es6/
Unlike other languages (for example: Java, C++, C), JavaScript doesn't support block scope. Once you declare a variable in a loop or in a function it's scope is within the function body if you do
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
here your i becomes a global variable and j become local to the function or script in which the loop is.
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
it is not correct to state that the above creates a global variable i. I believe you should always use var to declare variables (unless you are intentionally wanting a 'property' rather than a 'variable' -which is pretty unlikely in 99.99% of JS coding scenarios ...)
Omitting var when assigning an initial value to i isn't creating a local or even a global variable, it is creating a property i for the global object (which may seem/behave mostly like a global variable - but they have some subtle differences).
better would be:
var i;
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
now the loop is using a global variable i (or function local variable i, if this code appears in a function)
see more about this at what is function of the var keyword and variables vs. properties in Javascript
--
note, what is a little confusing is that you can re-declare a variable, for example in a second loop
for(var i=0; i<9; i++){
document.write('i = ' + i + '<br>');
}
for(var i=0; i<9; i++){
document.write('i = ' + i + '<br>');
}
this seems to be valid (no errors when I test). It seems that you CAN re-declare variables in JavaScript - but it probably isn't every a good idea, unless a special case - see this related question mentioning how [Google Analytics makes use of the 'safe' redeclaration of a variable] (Redeclaring a javascript variable)
there is some discussion about re-declaring variables in JS (and also loop variables like i) in this related SO question: declare variables inside or outside the loop
There is event a JavaScript pattern for single declaration of variables

Javascript for loop index variables become part of global scope?

Perhaps I'm not aware of how for loop index variables get scoped, but I was very surprised when one of my loops didn't complete, seemingly because a function called from within a loop contained an i for its for loop index as well.
Here's a little script I put together to demonstrate this behavior:
var loopOne = function(test) {
for(i = 0; i < test.length; i++)
console.log(getMask(test));
};
var getMask = function(pass) {
var s = "";
for (i = 0; i < pass.length; i++) {
s = s + "*";
}
return s;
};
loopOne('hello');
If I run this in Chrome and look at the console log, I should see ***** five times. However, I only see it once. Upon further inspection, if I type i in the Chrome javascript console, it will output 6 ( = 'hello'.length + 1). This makes me think that i has become a part of the global scope and is not limited to the scope of the for loop for which it was needed.
Is this correct? If so, what's a better practice for defining the index variable of a for loop in javascript?
In Javascript, variables are scoped with the var keyword. When declaring variables with var, the variable is scoped to the current function. When assigning to a variable without using the var keyword, it is assumed you're talking about an already defined variable in the same or a higher scope. If none is found, the variable is created in the highest scope.
Bottom line: declare all your variables using var.
You should declare your loop index variable with let:
for (let i = 0; i < test.length; i++) ...
That will declare and set the proper scope for the variable.
When you declare your variables with var, you scope them to the current execution context.
When you don't, they become properties of the global object (window in a browser).

Categories

Resources