Declaring variables inside or outside in a for-in loop - javascript

Having this two options:
Option A:
var index;
for (index in myObject) {
// Do something
}
Option B:
for (var index in myObject) {
// Do something
}
I don't know if in the option B the variable index it's being redeclared every time of the loop or just once.

Those two snippets of code do exactly the same thing (and that's the case in most language such as C, C++ and C# amongst others). If the variable was redeclared at every iteration, then following your logic, it would also be re-initialized, and would constantly loop over the same object. Your loop would be infinite.
On a side-note, in JavaScript, all variable declarations get pushed to the function scope; this means that you can declare variables anywhere within a function, even within nested loops, and they will only be declared once.
Link to the var documentation
Relevant SO question
Other relevant SO answer
Edit courtesy of #torazaburo:
If you want to declare a variable with a local scope (as in, a variable that will only be defined in the current block such as a for, while or if, you can use the let statement:
let var1 = 123;
It also allows you to override variables with the same name but declared in a higher scope, such as in this example from the docs:
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
See the full documentation (and examples) here.

The preferred approach in 2016 is to declare the variable in the loop head, using let:
for (let i = 0; i < max; i++) { }
^^^
There is probably minimal performance difference between this and other approaches, but there are major advantages in terms of the robustness and clarity of your code.
First, with let, i is local to the for construct, so it can't "leak out", or modify some other i in an outer scope.
Second, and perhaps more importantly, a new version of i is created for each iteration of the loop. In technical terms, "you get a fresh binding for each iteration if you let-declare a variable" (see this excellent article). This solves the age-old problem of closures created inside the for-loop using the final value of i. We can now just write
for (let i = 0; i < 10; i++) {
setTimeout(() => alert(i), i * 1000);
}
instead of having to do some clumsy work-around such as
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(() => alert(i), i * 1000);
}(i));
}
which has been the topic of countless questions here on SO, and which many of you have wasted far too many brain cycles learning.

Related

let behavior in a for loop

In the following example, how does the for loop know that it has to assign a new value to each i and not just assign the last i three times likes var does?
for (let i = 0; i < 3; i++) {
setTimeout(function() { console.log(i) }, 100);
}
Also, I've seen some explanations that mention let is block-scoped in a for loop.. But since let's lexical scope is the for loop (outside of the {block}), is it then "loop-scoped"? I've only heard of block/function/global scope, never a loop scope, so what exactly is a loop if not a function?
In a for loop, Variables that are declared with the let keyword are local to that specific statement. This is in contrast to variables that are declared with var which ARE NOT local to the loop and are actually set in the same scope as the loop itself and not its inside.
The actual scope is determined by the interpreter / runtime which ideally correctly implements sufficiently precise language specs (in this case see here).
The latter tell you that in 'for' loops, the scope of declarations in the initializer section is a 'virtual' block encompassing the overt block of the for loop. However, it gets a bit more complicated: for each iteration, the binding of declarations is renewed.
You could rewrite the code as follows to elicit equivalent behavior:
let i=42;
{
let i_shadow = 0;
while (i_shadow < 3) {
let i = i_shadow;
setTimeout(function() { console.log(`'i' written through 'setTimeout': ${i}`) }, 100);
i_shadow++;
}
console.log(`'i' inside virtual block: ${i_shadow}.`);
}
console.log(`'i' outside virtual block: ${i}.`);
The interpreter/runtime 'knows' about that behavior as the context o a 'for' loop has been lexically established at the time the declaration of i is encountered (*).
Compare to the original:
for (let i = 0; i < 3; i++) {
setTimeout(function() { console.log(i) }, 100);
}
console.log(`'i' outside virtual block: ${i}.`);
You may also want to have a look at this SO answer.
(*)
Note that in principle (ie. for other languages), the establishment of the lexical context at this position is no necessity: it all depends on the language semantics from the specs and their embodiment in compilers/interpreters and the runtime.

Must we include Let keyword in javaScript For Loops?

I am learning about For Looops and I find that the following two pieces of code work just the same.
Code 1:
for (let i=0 ; i<bobsFollowers.length; i++){
for ( let j=0; j<tinasFollowers.length; j++){
if (bobsFollowers[i] === tinasFollowers[j]){
mutualFollowers.push(tinasFollowers[i]);
}
}
}
console.log(mutualFollowers);
Code 2
for (i=0 ; i<bobsFollowers.length; i++){
for ( j=0; j<tinasFollowers.length; j++){
if (bobsFollowers[i] === tinasFollowers[j]){
mutualFollowers.push(tinasFollowers[i]);
}
}
}
console.log(mutualFollowers);
You can globally access the variable if you do not include let keyword
for (let i = 0; i < 3; i++) {
console.log(i);
}
for (j = 0; j < 3; j++) {
console.log(j);
}
console.log('j ', j); // accesible
console.log('i ', i); // inaccesible
Yes, if you do not specifically use the let keyword in a for, for...of or for...in loops etc, they will work the same as when you use the let keyword.
However, when you don't explicitly declare using let keyword, the variable will be declared as a var. let and const are block level variables, but you also need to understand that 'functions are not the only blocks, any { } is basically a block'. i.e. Once declared a 'var' will become a function scoped variable and in case it is not inside a function, and declared outside, then it becomes globally available, which is not such a good thing considering you might have multiple for loops using a variable named 'i' and if you don't use let, it will just keep incrementing the old 'i'. Please see the below two examples to understand what I mean by the above sentence:
const test = function(){
let let1 = 1;
var var1 = 2;
{
let let1 = 9; //This is a block scoped variable limited to this { } block
var var1 = 3; //re-initialization still overrides the original var 1 variable's value because once declared, the var variable is function scoped
console.log(let1); //9 - Block Scoped
console.log(var1); //3 - Function Scoped
}
console.log(let1); //1 - Function Scoped
console.log(var1); //3 - Still Function Scoped, always function scoped
}
test();
What I meant by globally incrementing value of 'i':
for(i=0; i< 2; i++){
console.log('first loop', i)
}
for(i;i< 5; i++){//I am not initializing i to 0, but I'm just trying to show that it is a global variable now.
console.log('second loop', i)
}
for(i; i< 7; i++){ //I am not initializing i to 0, but I'm just trying to show that it is a global variable now.
console.log('third loop', i)
}
Secondly, in ES5, Strict Mode was introduced, which basically is a way you can opt out of writing 'sloppy mode' JS code, and you can use it by specifying 'use strict'; globally or at a function level. And strict mode is used in most companies and developers in their professional code bases.
The point I want to convey with this is that 'Strict Mode' does not allow you to use for loops without declaring the variable, you have to explicitely specify the 'var' or 'let' keywords. Therefore it is always a good practice to declare your variables. You can read more about strict mode here: Strict Mode
Lastly, in the current post ES6 times, using the var keyword to declare variable is not considered as a good practice due to something called as Hoisting, which basically means that before the a var x; is declared, if you try to use it, you still can, however it's value will be 'undefined'. But in case of let you cannot use a variable before you declare it. You can read more about it Here : Hoisting
Also, in case of let if you try to access a variable before it's initialized, it throws you a Reference Error. This is because of a concept called as a 'Temporal Dead Zone'. You can read more about it here: TDZ
'let' is all about lexical scope, by default variables and objects in javascript have a global scope. As other have pointed out, using var will make the scope of variable global so anything can access and modify it.
Another use case for let would be in closures.
This example is from CS50's react native lecture 0 & 1.
Here makeFunctionArray returns an array of functions which print the value of i.
function makeFunctionArray() {
const array = [];
for(var i=0; i<5; i++) {
array.push(function () { console.log(i) });
}
return array;
}
const functionArray = makeFunctionArray();
functionArray[0]();
Now, what do you expect functionArray[0]() to print?
0, right? because we're invoking the function at index zero and it should console log 0.
But it doesn't print 0, instead it prints 5.
This is because 'i' has a global scope and will have a value of 5 when loop terminates.
the function(closure) we're returning from the makeArray function will still have access to 'i' and the value 5 gets wrapped up in it while being returned. so every functionArray[index]() will print 5.
This can be avoided with 'let' if 'i' is a let, its scope will only be the 'for' loop.
At the end of this lecture, this scenario is introduced and answered in next lecture
Yes, you have to. Or the old var
As other responses mention you will populate this variable in a broader scope.
Imagine this situation, You need to create a function that print the first 10 numbers:
function printNumbers(){
for (i=0; i<10; i++) {
console.log(i)
}
}
That's cool. Now you need to invoke this function 12 times, easy right?
function printNumbers(){
for (i=0; i<10; i++) {
console.log(i)
}
}
for (i=0; i<12; i++) {
printNumbers()
}
Well, if you execute this in your google chrome console (don't). You will fry your browsers. Since i will never reach 12 and you will be in an infinite loop.
You can test this safely by changing 12 by 5, you will see that the function only runs 1 time and not 5.
So it is not for your code (only), it is for who is going to use your code in the future. You are leaving a potential big fail in your code. Imagine it is in a library.
You have a good explanation already in StackOverflow about scoping and let here: What's the difference between using "let" and "var"?
Also about scope in general here: What is the scope of variables in JavaScript?
The scope of let is restricted to that block alone. but if you do not specify let keyword it is scoped to the global environment(the global scope of the browser is window object)
{
let a = 1;
b = 2;
}
console.log(a) //error
console.log(b) //2

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.

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

Can JavaScript get confused between local variables?

If I have a pair of functions that both set local variables, for example, the variable i in common for loops, and one happens to be called while the other is running, is there any danger of namespace confusion?
Keep in mind that JavaScript does not have block scope, but only function scope.
In addition, if you have nested loops, there will only be one i variable in the following example:
function myFunction() {
for (var i = 0; i < 10; i++) {
for (var i = 0; i < 10; i++) {
// code here will run 10 times instead of 100 times
}
}
// variable i is still accessible from here
}
Douglas Crockford recommends that the var statements should be the first statements in the function body in Code Conventions for the JavaScript Programming Language:
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
I think he has a point, as you can see in the following example, which will not confuse readers into thinking that the variables i and j are held in the scope of the for loop blocks:
function myFunction() {
var i, j; // the scope of the variables is now very clear
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
// code here will run 100 times
}
}
}
As long as you're using var, like this:
for(var i = 0; i < something; i++)
Then it's local and you're fine, if you don't use var, you have a global variable on your hands, and potential issues. Also if a for loop is nested in another, you should use a different variable name for each loop.
It will be a problem if are you referring to nested loops. Every time you enter the second for loop, the value of i (previously set in the outer for loop) will be reset.

Categories

Resources