JavaScript loop variable scope - javascript

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

Related

Is a variable declaration the same as a variable's binding?

MDN documentation states:
let bindings are created at the top of the (block) scope containing
the declaration, commonly referred to as "hoisting". Unlike variables
declared with var, which will start with the value undefined, let
variables are not initialized until their definition is evaluated.
Accessing the variable before the initialization results in a
ReferenceError. The variable is in a "temporal dead zone" from the
start of the block until the initialization is processed.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
Previously I thought the variable keyword and variable name together comprised a declaration, but in a question I asked recently, the answerer said they are actually an initialization.
I'm sorry for using two different terms when writing that MDN paragraph. For all purposes in that article, "variable" and "binding" should be understood as the same thing. But let's go into details.
A variable declaration creates the variable (as an abstract entity). It tells the compiler that it should introduce a new variable, and also can tell it about a name, a type to be held, an initial value, a scope etc. (depending on the language). In JS, there are different kinds of declarations that do different things, for example
var has a name, an optional initialiser and scoping rules specific to var
function has a (sometimes optional) name, the value is always given and known to be a function
const has a name, a required initialiser, should be immutable, and has lexical scoping
…
A binding is the association of a variable name with the variable entity, for example "x refers to the variable declared with class x". Such bindings depend on the scope, i.e. in every different scope there are different bindings and so the identifier x might refer to different things in different scopes.
Given the scoping rules of JavaScript, a variable declaration also causes bindings for itself to be created in the respective scopes.
So the binding is what makes the name available to be used. That's what I referred to as "the let binding is created at the top of the scope". It has nothing to do with the variable existing, having memory allocated for it, or being initialised.
A declaration just says that something exists. In JavaScript you can declare variables, functions and (more recently) classes.
In some languages (e.g. C, C++) it's possible to declare something without defining it. For example:
// this declares a function exists with a given signature, but doesn't define its implementation
void someFunction();
someFunction(); // here we call the function, since we know it exists
// here we define the function, which we have to do at some point
void someFunction() { /* ... */ }
This pattern is less common in modern languages, where the declaration and the definition tends to be combined, but it's useful to understand the distinction seeing as your question seems largely about terminology.
Variables can be declared, however they don't have definitions.
let b; // we declare that there's a variable 'b'
Instead you can assign a variable:
b = 5; // assignment
let c = 6; // declaration and assignment in one statement
The concept of binding in computer science has many forms. For example, when you type foo in your code, binding is the act of working out which variable/function/type/... should be used. In JavaScript this is pretty straightforward, but in some languages it can get pretty hairy (due to things like overload resolution and so forth).
However I don't believe that's what MDN means when they talk about let bindings. I believe it's a shorthand for "let declaration and assignment", as we saw above.
Regardless, I wouldn't worry too much about that term. The most important bit to understand from the paragraph you've quoted is that let and const are tighter versions of var, introduced in recent versions of the language to address pitfalls and surprises that came from the way var works.
Previously I thought the variable keyword and variable name together comprised a declaration
You're right.
var a;
var b = 1;
let c;
let c = 2;
const d = 3;
These are all declarations of variables (even though const technical variables can't vary, or more precisely, they cannot be reassigned).
It's just that var is a bit sloppy and surprising.
You could declare a var more than once within the same scope:
var a = 1;
var a = 2;
This won't work with let:
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared
Scoping on var can be surprising too:
for (var i = 0; i < 10; i++)
{
var inner = 1;
}
console.log(inner); // prints 1 even though you might think this would be an error
Or worse:
for (var i = 0; i < 10; i++)
{
for (var i = 0; i < 10; i++)
{
console.log('hello');
}
}
At a glance you might think this would print hello 100 times (10*10), but actually it is only printed 10 times because both loops use the same variable. This is a type of programmer error that the language should really prevent. If that code used let i instead, it would produce a syntax error.
As for hoisting you can think of it as though all the var declarations were moved to the top of the containing function.
function foo()
{
doThing();
var i = 0;
doSomethingElse();
for (var j = 0; j < 10; j++)
{
var k = 10;
}
}
Even though that's how you might write the code, it behaves as though you had written:
function foo()
{
var i; // all declarations hoisted to top of containing function scope
var j;
var k;
doThing();
i = 0;
doSomethingElse();
for (j = 0; j < 10; j++)
{
k = 10;
}
}
This is why you can write:
i = 10;
var i;
The var is moved up in the code, so it behaves as:
var i;
i = 10;
You can think of let as not being moved. Therefore it is an error to reference it before it is declared.
The main thing to understand here is that the js engine actually visits a let statement inntwo different situations (as well as every other statement, but it particularily matters here). It is visited once during parsing, when it generates an AST and also analyzes the scopes and the variables. It also creates a list of variables for each scope. Now when the code gets executed, the engine visits the statement a second time (or more often if its inside a loop / function / whatever) and now finally initializes the variable and assigns a value to it. So "hoisting" is basically just caused because of the parsing / executing stages, the engine knows that a variable exists before it reaches the declaration statement during execution as it has already parsed it before.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
The keyword actually causes an entry in the scope record, which will then get turned into a storage space during execution. On the other hand the statement itself causes an initialization during execution. So its actually hard to say when a declaration happens, thats a question of words. Its common to say
That variable was declared at line 10
Its declared in that block
so wether "declaration" refers to the statement or the scope assignment is up to you :)
the answerer said they are actually an initialization.
Actually the answerer prefered to call it "initialization" and not "declaration" to not confuse readers, but well in reality its confusing as human languages are not as clearly defined as machine ones.

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.

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

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();
}

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:

About scoping in JavaScript

I need to have some information about the scoping in JavaScript. I know that it supports lexical (static) scoping, but, does not it support dynamic scoping as well?
I think you're confused because Javascript uses static scoping but at function-level, not at block level like usual structured languages.
var foo = "old";
if (true) {var foo = "new";}
alert (foo == "new")
So be careful, blocks don't make scope!
That's why you sometimes see loops with functions inside just to enable variables whose scope is inside an iteration:
functions = [];
for(var i=0; i<10; i++) {
(function(){
var local_i = i;
functions[local_i] = function() {return local_i;}
})();
}
functions[2]() // returns 2 and not 10
As far as I understood; Javascript has two kinds of variables which are global and local variables. But, suppose we have a variable called x, which is defined as global, and defined in the static parent of the scope of place where x is referenced. In this case, x takes the value of the global variable. Thus, global variable has higher priority than local ones. And, when there is no any global variables, x finds the declaration through the static chain which makes me think that Javascirpt is staticaly scoped language.
Am I right at above?

Categories

Resources