JavaScript variable hoisting behavior [duplicate] - javascript

This question already has answers here:
Are variables declared with let or const hoisted?
(7 answers)
Closed 4 years ago.
I'm probably missing something very fundamental but I would like to ask this regardless
var a=100;
function f(){
console.log(a)
const a=150
}
console.log(a)
f();
Prints 100 and throws an error while changing const a=150 to var a=150 returns 100 and undefined. I'm unsure why this behavior occurs and any pointers to relevant info is appreciated

In general, this is how hoisting works:
the declaration of the variable is moved to the top
the variable is initialized with a special "hoisted" value
when the program reaches the var/let/const line, the variable is re-initialized with the value mentioned on that line (or undefined if there's none).
Now, your example can be simplified down to this:
console.log(a)
let a = 150
which is actually:
a = <hoisted value>
console.log(a)
a = 150
It throws an error because, for let and const, the hoisted value is a special object that raises an error when you try to access it.
On the other side, the hoisted value for var is just undefined, so this will print undefined without throwing an error:
console.log(a)
var a = 150
Also, there's some confusion (including this very thread) about which variable types are hoisted, and a so-called "dead zone" for let/const vars. It's simpler to think of things this way: everything is hoisted, that is, all variable bindings in a block are created before entering the block. The only difference between var and let/const in this regard is that with the latter you are not allowed to use a binding until you initialize it with a value.
See https://stackoverflow.com/a/31222689/989121 for more details.

const and let have temporal dead zone so when you try to access const or let before it is instantiated you get an error.
This is not true for var. var is hoisted at the top meaning it is instantiated with a value of undefined just before a function code is run.

The problem is that with new ES6, let and const, hoisting is not applied what this means is that a variable declared with either let or const cannot be accessed until after the declaration, if you do this will throw and error
var a=100;
function f(){
console.log(a)// throws an error because is accessed before is declared....
const a=150
}
console.log(a)
f();
This is commonly called the Temporal Dead Zone
On the other hand using Var will apply hoisting what this does is defines the variable in memory before all the scope is executed...
var a=100;
function f(){
console.log(a)// This won't throw an error
var a=150
}
console.log(a)
f();

the problem is
the variable with const cannot be declared more then once,
and when you declares const a=150 inside a function, it deleted the previous variable and this is why the error is coming

I think the answer your looking for is const is block scope and is not hoisted, whereas var is hoisted.
That's why you get 100, "Error: a is not defined" with:
var a=100;
function f(){
console.log(a)
const a=150
}
console.log(a)
f();
and 100, undefined with:
var a=100;
function f(){
console.log(a)
var a=150
}
console.log(a)
f();
In the second instance a is declared, but it is not defined yet. You'll see the same result with:
function f() {
console.log(a)
var a=150
}
console.log(a)
f();
Since the var inside the function is hoisted.
Bottom line: const variables are not hoisted, var variables are.

Related

Hoisting of let, const with separate initialization

In Documentaion said that let and const are hoisted.
Variables declared with let and const are also hoisted but, unlike var, are not initialized with a default value. An exception will be thrown if a variable declared with let or const is read before it is initialized.
Also there are a pretty clear sample there:
console.log(num); // Throws ReferenceError exception as the variable value is uninitialized
let num = 6; // Initialization
But I don't understand why this rise the ReferenceError also:
x = 9
console.log(x) // Why: "Throws ReferenceError exception as the variable value is uninitialized" here ?
let x;
Specs says 'let' supports hoising. Initialization is going before using this variable. What's wrong?
If the reason of the ReferenceError is TDZ then why in specs says that 'let' supports hoising, becouse of TDZ and hoising are mutually exclusive things... And what could be an example of hoising for 'let' if I can't use this varibable before declaration...
Why throws ReferenceError exception as the variable value is uninitialized here, in the console.log line?
It doesn't. It throws it on access of the variable, which includes assignment:
x = 9; // exception happens here already!
let x;
You cannot use an uninitialised variable at all. It only gets initialised when the let/const statement itself is evaluated.
What could be an example of hoisting for 'let' if I can't use this variable before declaration?
You cannot use it, but you can refer to it, e.g. by creating a closure over it:
function log() {
console.log(x);
}
// log(); - would fail here
let x = 9;
log();
Also it means that referring to x will actually refer to that uninitialised variable, not some other x from an outer scope. See Are variables declared with let or const hoisted? for more.

Java Script Scoping

Js community I am new in JS and I have a confusion with JS scopes in this example I have an if statement and I defined inside the block var age and this a local scope then I console log this variable age and I got 25 this is why? is it because of the if statement is defined globally so what is defined inside the block is global too? one more thing I noticed the age variable is attached to the global object which is the window I logged it and I found the age var but I am not sure why this is happening?
if(true){
var age = 25;
}
console.log(age);
You have some misunderstandings that should be addressed:
Hoisting
var is hoisted to local scope(before evaluation)
console.log(a) // undefined
var a = 25
console.log(a) // 25
let and const are lexical scoped:
{ // this is a block scope, and will only be a scope when evaluated since it is standalone
console.log(a) // reference error
let a = 25;
console.log(a) // 25
}
console.log(a) // reference error
showing what happens with statement blocks
if (true) {
let a = 25;
}
console.log(a) // reference error
Control Statements
if statements will only execute if the evaluate to true. true is true. Thus your if statement will always fire in your example and set the hoisted variable to 25.
How you should think of it
console.log(a) // undefined since a got hoisted to top of local scope, which is currently global
var a;
if (false) a = 25;
console.log(a) // undefined
if (true) a = 25;
console.log(a) // 25
More information and what it does to function decleration
If I understand correctly this is due to a concept called hoisting, variable declarations are moved to the top of the current function scope, not block scope.
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

Why doesn't this assignment throw a ReferenceError?

Consider three cases, where both a and k are undefined:
if (a) console.log(1); // ReferenceError
and
var a = k || "value"; // ReferenceError
seems reasonable, but...
var a = a || "value"; // "value"
Why doesn't the last case throw a ReferenceError? Isn't a being referenced before it's defined?
This is because of one of var's "features" called hoisting. Per the link:
Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code. (emphasis mine)
So, for example:
console.log(a);
var a = "foo";
Instead of throwing a ReferenceError as you might expect, since a is referenced before it is defined, it logs undefined. This is because, as mentioned earlier, the declaration is processed first and essentially happens at the top, which means it's the same as:
var a;
console.log(a);
a = "foo";
The same goes for functions as mentioned earlier:
function foo() {
console.log(a);
var a = "foo";
}
That's the same as:
function foo() {
var a;
console.log(a);
a = "foo";
}
To see why, look into the ECMAScript 2015 Language Specification:
13.3.2 Variable Statement
NOTE
A var statement declares variables that are scoped to the running execution context’s VariableEnvironment. Var variables are created when their containing Lexical Environment is instantiated and are initialized to undefined when created.
[...]
A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the VariableDeclaration is executed, not when the variable is created. (emphasis mine)
From this, we can gather that the var declarations are created before any code is executed (in their lexical environment) and are scoped to the containing VariableEnvironment, which is either in the global scope, or in a function. They are initially given the value undefined. The next part explains that the value that the var is assigned to is the value of the right hand side when the declaration is executed, not when the variable is created.
This applies to your situation because in your example, a is referenced like it is in the example. Using the information earlier, your code:
var a = a || "value";
Can be rewritten as:
var a;
a = a || "value";
Remember that all declarations are processed before any code is executed. The JavaScript engine sees that there's a declaration, variable a and declares it at the top of the current function or global scope. It is then given the value undefined. Since undefined is falsey, a is assigned to value.
In contrast, your second example throws a ReferenceError:
var a = k || "value";
It can also be rewritten as:
var a;
a = k || "value";
Now you see the problem. Since k is never a declared anywhere, no variable with that identifier exists. That means, unlike with a in the first example, k is never declared and throws the ReferenceError because it is referenced before declaration.
But how do you explain var a = "123"; var a = a || "124"; // a = "123"?
From the ES2015 Language Specification again:
Within the scope of any VariableEnvironment a common BindingIdentifier may appear in more than one VariableDeclaration but those declarations collective define only one variable.
To put it plainly: variables can be defined in the same function or global scope more than once, but always define the same variable. Thus, in your example:
var a = "123";
var a = a || "124";
It can be rewritten as:
var a;
a = "123";
a = a || "124";
Declaring a in the same function or global scope again collectively only declares it once. a is assigned to "123", then it is assigned to "123" again because "123" is truthy.
As of ES2015, you should, in my opinion, no longer use var. It has function scoping and can cause unexpected assignments like those mentioned in the question. Instead, if you still want mutability, try using let:
let a = a || "value";
This will throw a ReferenceError. Even though all variables are hoisted, no matter which declarator you use (var, let, or const), with let and const it is invalid to reference an uninitialized variable. Also, let and const have block scope, not function scope. This is more clear and normal regarding other languages:
function foo() {
{
var a = 3;
}
console.log(a); //logs 3
}
Versus:
function foo() {
{
let a = 3;
}
console.log(a); //ReferenceError
}
var a = k || 'value';
var a = a || 'value';
a is declared when you call var a but k is not, that why first line is ReferenceError and second line is 'value'
if (a) console.log(1); // ReferenceError
in this case i think there is no doubt as a is not declared anywhere before using it so refrence error
var a = k || "value"; //ReferenceError
same case here k is not declared and we are trying to use it
var a = a || "value"; //"value"
now in this case when we are trying use a (a in r.h.s) that time a is already declared before using it and hence no error
Adding to this if you want to know difference between reference error and undefined
refrence error -indicate variable is not declared yet whereas
undefined - it is special value in javascript assigned to any variable as soon as it is declared undefined indicates that variable is declared but has not taken any value

explanation on hoisting in javascript [duplicate]

This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 7 years ago.
I am learning javascript hoisting and came across a scenario for which I need a bit more explanation. Below is the program that I have
test();
console.log("The value of data is "+data);
function test(){
console.log("Hello");
}
var data = 15;
If I run the above program in JsFiddle, I am getting the below output:
Hello
The value of data is undefined
Is the data hoisted? I am seeing the console as undefined so I presume that the data variable is hoisted.
Is variable hoisting only inside the function? In the above program, if the data is hoisted does that imply that the data variable hoisted even at global level?
The above program prints the text Hello when I define the function without a variable. So is this referred to as function hoisting or is it global function?
If the var data = 15 is changed to data = 15, then I get the error: Uncaught ReferenceError: data is not defined. Why is it behaving differently than in case of function?
Please help me understand what I am missing here.
Is the data hoisted? I am seeing the console as undefined so I presume that the data variable is hoisted.
The binding is hoisted and it's always initialized to undefined, this means data exists but there hasn't been an assignment yet.
Is variable hoisting only inside the function? In the above program, if the data is hoisted does that imply that the data variable hoisted even at global level?
Hoisting happens either way, but variables defined inside inner functions aren't hoisted to the script/function that contains them. So var a inside a function fn won't be available on the outer scope.
The above program prints the text Hello when I define the function without a variable. So is this referred to as function hoisting or is it global function?
Javascript understands function differently depending on the context. When you define a function like this:
function fn(){
}
It's considered a function declaration, when you write something like this:
var fn = function(){ };
The function part is considered a function expression. The expression is evaluated when it reaches that point in the script. While the declaration is hoisted to the top. They both produce a fn in their relevant scope, it's just that one is hoisted the other one isn't.
If the var data = 15 is changed to data = 15, then I get the error: Uncaught ReferenceError: data is not defined. Why is it behaving differently than in case of function?
When you removed the var portion, the binding is no longer hoisted. In non-strict mode, the binding will be available after the assignment. In strict mode not only does reading data will fail, but also the assignment will fail.
Your program :
test();
console.log("The value of data is "+data);
function test(){
console.log("Hello");
}
var data = 15;
is actually executed as though you had written :
var data; // declaration of data hoisted
function test(){ // Also function definition
console.log("Hello");
}
test(); // Show 'Hello'
console.log("The value of data is "+data); // Data still has no value!!
data = 15; // Now data has the value 15.
In short the declaration of variables and functions are hoisted, the
assignment of values remains where you write them.
Now as an exercise, what does this produce :
test();
var test = function test(){definition
console.log("Hello");
}
console.log("The value of data is "+data);value!!
data = 15;
and why?

Variables defined in global scope with identical names

Can anybody explain, why next js code rises two alert windows with 'string1' text rather than to rise the second with 'undefined' text inside?? If both variables are described in the same scope..
var a = 'string1';
alert(a);
var a;
alert(a);​
http://jsfiddle.net/FdRSZ/1/
Thanks
Variable declarations (and function declarations) are hoisted to the top of the scope in which they appear. Assignments happen in place. The code is effectively interpreted like this:
var a;
var a;
a = 'string1';
For example, consider what happens if you declare a variable inside an if statement body:
console.log(myVar); //undefined (NOT a reference error)
if (something === somethingElse) {
var myVar = 10;
}
console.log(myVar); //10
Because JavaScript does not have block scope, all declarations in each scope are hoisted to the top of that scope. If you tried to log some variable that was not declared, you would get a reference error. The above example is interpreted like this:
var myVar; //Declaration is hoisted
console.log(myVar);
if (something === somethingElse) {
myVar = 10; //Assignment still happens here
}
console.log(myVar);
So even if the condition evaluates to false, the myVar variable is still accessible. This is the main reason that JSLint will tell you to move all declarations to the top of the scope in which they appear.
In slightly more detail... this is what the ECMAScript 5 spec has to say (bold emphasis added):
For each VariableDeclaration and VariableDeclarationNoIn d in code, in
source text order do
Let dn be the Identifier in d.
Let
varAlreadyDeclared be the result of calling env’s HasBinding concrete
method passing dn as the argument.
If varAlreadyDeclared is false, then
Call env’s CreateMutableBinding concrete method passing dn and
configurableBindings as the arguments.
Call env’s SetMutableBinding concrete method passing dn, undefined, and strict as the arguments.
So, if a binding already exists with the identifier we are trying to bind now, nothing happens.
Thats because JavaScript does something called variable hoisting. In fact, your JS looks like this:
var a; // hoisted -> declared on top
a = 'string1';
alert(a);
alert(a);
See How Good C# Habits can Encourage Bad JavaScript Habits for more details on how JavaScript works.
That's because the second var a isn't a separate variable declaration. As far as the javascript interpreter is concerned it is the same a as the first one.
var means "Scope this variable to this function" not "Set the value of this variable to undefined".
If the variable is already scoped to the function then var foo means the same as just plain foo

Categories

Resources