A while ago, I read some article about using let and var in JavaScript and they're saying that a variable you declare using "var" keyword (even in for loop) works only within it's function, so why is it possible to make multiple for loops in one function, each of them look like : for (var i = 0; i < array.length; i++);
and JavaScript has no problem with "redeclaring" the i variable? Thanks :)
JS has a special case for var as it allows hoisting, which means multiple declaration of the same variables is allowed and they got moved to the enclosing functional scope. However they are still the same variable. Consider the following code:
function foo(){
for(var i=0; i<3; i++){
console.log("x");
}
for(var i;i<6;i++){
console.log("y");
}
}
foo()
Notice there is no initialization of i in the second loop, but it will execute fine and produce 3 x and 3 y. It used to be a problem with old browsers, but new browser simply allows it with no error given.
A seemingly small question with a complex answer. var is the old method declaration. You can declare it anywhere and as many times as you want. JavaScript will not care. All declared variables are available immediately, because declaration gets moved up to the very beginning of the function's code. This is known as hoisting.
let is the new way of declaring variables. const exists, but we're not interested in that right now. let is block scoped. The rules behind let and scoping can be confusing, but it's advantageous to learn/understand. It is the future of JavaScript. I thoroughly talk about it in my blog post, here.
let gives you the privilege to declare variables that are limited in scope to the block, statement of expression unlike var.
var is rather a keyword which defines a variable globally regardless of block scope.
ES6 introduced the 'let' keyword to tackle this issue only. It allows a variable to be bound to its scope within a function so that you cannot re-declare it outside preventing hoisting issues. Example -
for(var i=0; i<5; i++) {
console.log(i);
}
console.log(i);
Here the output will be - 0 1 2 3 4 5
Instead of 5 we must get 'Uncaught Reference Error' since variable i should be accessible only within the function. Because of Hoisting in JavaScript, all the variables and function names are stored to one place before execution. So the code actually looks like the following -
var i;
for(i=0; i<5; i++) {
console.log(i);
}
console.log(i);
This is resolved if you use the let keyword.
Related
I have read my blog about the var and let. What I see is this.
var is a function or global scope variable depend on where it is defined.
where
let is block scope variable
So in lots of articles, I see they recommend to use let instead of var. I understand that because it eliminated the conflict of the scope of a variable.
So I want to ask where to use let and where to use var? If possible please provide any relevant link for that. If I go with recommendation than I have to use let everywhere.
What I understand is this.
let should be used in for loop as it creates its own lexical scope.
for(let i =0;i<5;i++){
setTimeout(function(){
console.log(i);
},100);
}
So in this case because of let, we will able to print 0,1,2,3,4, but if we have used var it would have print 5 time 5.
Also, I want to know your suggestion on what should be used in function scope and global scope?
let say, I have file index.js
var first = 1; // what should be used here and why
function function1(){
var first = 1; // what should be use here and why `let or var`
var first1 = 2; // what should be use here and why `let or var`
for(let i=0;i<2;i++){
console.log(i);
}
Also, I fill let is more than a variable, I create its own lexical scope, there would be more manipulation under the hood like creating IIFE sort of thing.
What I understand is that we should use function and global scope as var and let as only block scope? Please provide any recommended link which describes what is better where and why?
Thanks.
It's mostly right to only use let these days.
In almost all situations, let is a better or at least equivalent to var considering that leaky declarations make you write error prone code. Avoid using var.
Look at this code:
for(var i = 0; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
contrary to this code:
for(let i = 0; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
The first one makes a closure which catches i, defined by var, while the other one makes i different values. The first example makes every callback alert 6, since they are all pointing to the same object. However, the let in the second example makes a new block scope every time it iterates. This solves a very common pitfall in javascript.
In most situations, if you need to use var's scope to achieve something not available using let, it's almost always a sign that's something is wrong.
Also, don't rely on var's variable hoisting. If you are using a variable you didn't declare before, it becomes error prone.
Mostly, try to follow on the style guide you follow. If you don't have a special style guide you follow, try the AirBnB's: https://github.com/airbnb/javascript
The "never use var and use let" thing is mentioned here: https://github.com/airbnb/javascript#variables
let and var
You should use var, when you wan to define a variable globally, or locally to an entire function regardless of block scope. Variables assigned with the var keyword have functional scope. The variable isn’t accessible outside of the function.
And, you should use let to declare variables that are limited in scope to the block, statement, or expression on which it is used. When used inside a block, let limits the variable's scope to that block.
Variables assigned with let are very similar to those defined with var. The major difference is scope. This has been referenced above. Variables assigned with let have block scope. This means the variable can be seen within that block and any sub-blocks. Variables assigned with var have functional scope and ignore block scoping rules. Variables assigned with let can not be redeclared, they can only be reassigned.
According to this article, Only use the let keyword when you know that a variable will have a dynamic value. You probably don’t need to use var anymore
Clearly, you know the difference between let and var, and your question is WHERE TO USE WHICH?
First of all, if you are seeking for a better performance, use let wherever you are able to. However, you have to be aware that some old browsers may not be able to handle the let.
Second, I think the best and shortest answer to your question is " use let as long as you can, and if you couldn't then use var".
If you study the differences between let and var deeply, you can figure out where you should use var instead of let, I recommend you to read this article.
I am interested how for loop operate behind the scenes in ES6.
This is the basic example
var funcs = [];
for (let i = 0; i < 5; i++) {
funcs.push(function () {
console.log(i);
});
};
The reason each function will get proper i value (from 0 to 4) is because let is creating 5 new scopes and functions are bound to their corresponding scope. Thats what I think and that makes most sense to me. If that is the case then it doesnt make sense why const declaration (i) is failing since it should be creating 5 new scopes and const variables can live happily in different scopes.
Before let we have do use IIFE in order to achieve the same effect, but what that code did is that it basically created new scopes for the functions and I thought let is doing the same behind the scenes.
If the above statement is not correct, then it must be that let inside for loop is only creating one scope but then I do not get how is that different from var declaration and how functions get proper i value. To make it even more clear, lets say that let is bound to one new scope which is created by the for loop and var declaration is hoisted to the global scope in this case but thats still one scope to be working with.
Can anyone share some light on this topic?
The reason each function will get proper i value (from 0 to 4) is because let is creating 5 new scopes and functions are bound to their corresponding scope.
Yes, this is what happens. See Explanation of `let` and block scoping with for loops for details (actually there are 6 scopes).
If that is the case then it doesnt make sense why const declaration (i) is failing since it should be creating 5 new scopes and const variables can live happily in different scopes.
Your false assumption here is that const works the same as let. Yes, it would totally be possible for 5 consts to be created in the loop body evaluations. But that just doesn't make sense for a loop like
for (const i=0; i<5; i++) {
console.log(i);
}
which would lead to a TypeError: Assignment to constant variable - you cannot increment a const. So you shouldn't use it in a for loop (notice that for…in and for…of loops are different again).
OK, one could write something like
let i=0; for (const j=i; i<5; i++) …
and expect it to work and get 5 different const j variables in the body. But that's not what happens either, as that's a totally weird way to write this. If you want a const declaration in each loop iteration, better write it explicitly:
for (let i=0; i<5; i++) {
const j=i;
…
}
which is clean and clear and actually does what you might have expected above.
How const declarations in for loops are actually meant to be used can be shown in this example:
for (const iterator = {…}; iterator.hasNext(); iterator.step()) {
… iterator.getValue() …
}
If we check the spec, this actually has the same effect as
{
const iterator = {…};
for (; iterator.hasNext(); iterator.step()) {
… iterator.getValue() …
}
}
which means that the constant is declared once in the head of the loop. It doesn't make sense to re-declare it in every iteration, after all its value is constant anyway.
Is this ok?
for (var i = 0; i < 10; i++) {
...
}
doSomething(i);
Obviously I expect i to have the value 10 here. My testing indicates it's ok, but is this defined behaviour? (ES5)
Yes, this is defined behavior. The current version of JavaScript doesn't have block scoping, there is only function scope.
However, the new standard of JavaScript (ES6) is introducing a let statement (an alternative to var), which will respect block scope.
In the following code, you would not be able to access i outside of the loop:
for (let i = 0; i < 10; i++) {
...
}
This is really a question of scope. Do you want i to be accessible outside the for loop?
If so, and you want to make sure, define i outside the loop. Something like:
Duh... Variables in for loops aren't blocked (barring the let option in ES6). Which I already knew, but I'm tired and spaced it. So of course i will be accessible, and defining it outside the for loop is entirely unnecessary.
I'm going to leave this up as a reminder to myself not to jump the gun when I'm tired and haven't fully thought through my answer.
var i;
for(i = 0;i < 10; i++) {
...
}
doSomething(i);
Edit: After double-checking, i is definitely going to be accessible no matter what, and that is defined behavior, so it's safe either way.
Before asking my question, let me give a disclaimer. I know what var does, I know about block scope, and I know about variable hoisting. I'm not looking for answers on those topics.
I'm simply wondering if there is a functional, memory, or performance cost to using a variable declaration on the same variable more than once within a function.
Here is an example:
function foo() {
var i = 0;
while (i++ < 10) {
var j = i * i;
}
}
The previous could just have easily been written with the j variabled declared at the top:
function foo() {
var i = 0, j;
while (i++ < 10) {
j = i * i;
}
}
I'm wondering if there is any actual difference between these two methods. In other words, does the var keyword do anything other than establish scope?
Reasons I've heard to prefer the second method:
The first method gives the appearance of block scope when it's
actually function scoped.
Variable declarations are hoisted to
the top of the scope, so that's where they should be defined.
I consider these reasons to be good but primarily stylistic. Are there other reasons that have more to do with functionality, memory allocation, performance, etc.?
In JavaScript - The Good Parts Douglas Crockford suggests that by using the second method and declaring your variables at the top of their scope you will more easily avoid scope bugs.
These are often caused by for loops, and can be extremely difficult to track down, as no errors will be raised. For example;
function() {
for ( var i = 0; i < 10; i++ ) {
// do something 10 times
for ( var i = 0; i < 5; i++ ) {
// do something 5 times
}
}
}
When the variables are hoisted we end up with only one i. And thus the second loop overwrites the value, giving us an endless loop.
You can also get some bizarre results when dealing with function hoisting. Take this example:
(function() {
var condition = true;
if(condition) {
function f() { console.log('A'); };
} else {
function f() { console.log('B'); };
}
f(); // will print 'B'
})();
This is because function bodies are hoisted and the second function overwrites the first.
Because searching for bugs like this is hard and regardless of any performance issues (I rarely care about a couple of microseconds), I always declare my variables at the top of the scope.
There will not be any differences during execution time. There might be a imperceptibly small difference in interpretation/compilation time, but that of course will be implementation dependent. There also might be a few bytes different in the size of the file, which could also affect download time. I don't think either of these are worth being bothered about.
As you already know, any variable declaration will be hoisted to the top of the function. The important thing to note is that this occurs during the interpretation/compilation process, not during execution.
Before a function is executed, the function must be parsed. After each function is parsed, they will both have all of the variable declarations moved to the top, which means that they will be identical and there will be no execution time cost incurred.
For the same reason, there are no memory cost differences. After parsing, there will be no differences at all.
Since you are not asking about style I am not telling you which I think is better. But I will say that the only reason you should prefer one over the other is style.
Style
Subjective. I prefer the approach that keeps the var close to the usage site, but I always keep the scoping rules in mind. I also avoid combining multiple declarations into a single var and prefer multiple var statements.
Memory allocations
Variables are not objects: not applicable. Due to the hoisting rules, the variable "slot" has the same lifetime in all cases.
Performance
No. There should be no difference in terms of performance. While an implementation could technically really mess this up - they don't.
The only way to answer this (besides looking at every implementation in minutia) is to use a benchmark.
Result: noise differences on modern browsers
The 2nd way saves the 4 characters in the the javascript file - but in terms of the actual code generation or execution speed I don't believe there is any difference at all.
Your example will function exactly the same. It could be even more unclear than your example to use 'var' in a block, though. Say, for example you want to update a variable that is outside of the scope (by not using 'var') conditionally, or use a local 'var' instead. Even if that condition is false, 'j' becomes local. It turns out not to be as trivial as it appears to do that.
var j = 1;
function foo () {
j = 2;
if (false) {
var j = 3; // makes `j = 2` local simply for being in the same function
}
console.log(j);
}
foo(); // outputs 2
console.log(j); // outputs 1
That's one tricky case that may not work as you expect just by looking at the code.
There are no downsides to declaring every 'var' on top, only up-sides.
I'm sure I've read a discussion on SO about this but can't find it. Simply, are there cons to declaring a for loop's increment inside the loop's declaration? What is the difference between this:
function foo() {
for (var i=0; i<7; i++) {
// code
}
}
...and this:
function foo() {
var i;
for (i=0; i<7; i++) {
// code
}
}
Since JS has function scope, either should be fine, right? Are there edge cases where the former approach would cause problems?
If they are identical, why is Crockford/JSLint all, "No way dawg," about it?
These are exactly the same. All local variables in javascript have function scope which means they are alive for the entire function they are declared in. This is often counter intuitive at first as most curly brace languages scope the life time of the variable to the block they are declared in.
A portion of Javascript developers very much prefer the second form. The rationale is that since all variables have function scope, you should declare them at the function level to make the life time explicit even for those not familiar with Javascript. This is just a style though and by no means a hard rule
EDIT
Note that with the introduction of ES6 let, you can now use let inside your loop for real block-scoped variable more details
for(let i = 1; i <= 5; i++) {
setTimeout(function(){
console.log('Value of i : ' + i);
},100);
}
The problem with declaring with var in the loop header is that it's deceptive. It looks like you're declaring a variable whose scope is limited to the for loop, when it actually exists everywhere within the function - including before the declaration:
var i = 1;
function foo() {
console.log(i); // 'undefined'
for (var i=1; i<100; ++i) {
}
}
Even though the console.log call occurs before the declaration of the local i, it is still in scope for it because it's inside the same function. So the local i, which has not yet had any value assigned to it, is what gets passed to log. This can be surprising; it's certainly not obvious to anyone who's not familiar with Javascript scoping rules.
Starting with ECMAScript 2015, there is a better way to declare variables: let. Variables declared with let are local to the block containing them, not the entire function. So this version of the above code will print 1 as intended:
let i=1; // could use var here; no practical difference at outermost scope
function foo() {
console.log(i); // 1
for (let i=1; i<100; ++i) {
}
}
So best practice in modern Javascript is to declare variables with let instead of var. However, if you are stuck with a pre-ECMAScript 2015 implementation, it's a little less confusing to declare all variables at the top of the function, rather than waiting till first use.
There's no difference, but I prefer the second way (per Crockford) because it explicitly shows that the variable to available outside of the for loop:
function() {
for(var i=0; i<7; i++) {
// code
}
// i is still in scope here and has value 7
}
Those are both exactly the same thing.
The two code block are identical. The first statement of the for loop is executed before the for loop starts, the loop is running while the second statement is true, and the third statement is run every time the loop iterates once.
This means that
for(var i = 0; i < 8; i++) {
//some Code
}
is identical to
var i = 0;
for(;i < 8;) {
//some Code
i++;
}
(The semicolon following the ( is to tell the computer that i < 8 is actually the second statement, not the first).