I am learning about variable hoisting in JavaScript, and found this behavior weird:
var x = 0;
(function () {
//Variable declaration from the if statement is hoisted:
//var x; //undefined
console.log(x); //undefined
if (x === undefined) {
var x = 1; //This statement jumps to the top of the function in form of a variable declaration, and makes the condition become true.
}
}());
Is it correct, that in this case, the statement makes the condition true so it can be executed?
Hoisting hoists only the declaration, but not the assignment. Your code is equivalent to:
var x = 0;
(function () {
//Variable declaration from the if statement is hoisted:
var x;
console.log(x); //undefined
if (x === undefined) {
x = 1;
}
}());
The if statement's condition expression evaluates to true and x = 1 is reached.
By the way ,if you declare a variables in a if statement ,No matter the if condition pass or not pass,the declaration is always hosited.For example:
console.log(a); //undefined , not respond ReferenceError ,it has been hoisted
if(true){
var a=1;
}
console.log(b); //same as above
if(false){
var b=1;
}
Related
I am reading something on Variable Hoisting that I am not able understand exactly how to learn around it. I read W3C schools for the explanation. But, based on the sample code, I could not make what is hoisting.
code 1 [This is the code from w3c school]
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
var x = 5; // Initialize x
var y; // Declare y
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x + " " + y; // Display x and y
y = 7; // Assign 7 to y
</script>
</body>
</html>
But the above code still displays 'undefined' for the variable y.
If I change the code as follows then it works fine. But, this below code is usual and not the different one to understand 'hoisting'
<script>
var x = 5; // Initialize x
var y;
y = 7;
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x + " " + y; // Display x and y
</script>
Any help on this to understand 'Variable hoisting'?
(Note: I've added a brief discussion of ES2015's let and const at the end of this answer.)
Fundamentally, what variable hoisting means is that no matter where you see var in any given scope, it's as though it were at the very beginning of the scope. So these are all identical:
function foo() {
var a = 42;
}
function foo() {
var a;
a = 42;
}
function foo() {
a = 42;
var a;
}
function foo() {
var a;
a = 42;
var a;
}
They're processed by the JavaScript engine as though they were:
function foo() {
var a;
a = 42;
}
Here's an example actually using variable hoisting, and also giving an example of what I call The Horror of Implicit Globals (that's a post on my anemic little blog):
function foo() {
a = 42;
b = 67;
console.log(a); // 42
console.log(b); // 67
var a;
}
foo();
console.log(typeof a); // undefined
console.log(typeof b); // number?!
console.log(b); // 67?!
Why does b exist outside of foo? Because inside foo, these two lines do very different things:
a = 42;
b = 67;
The first line sets the local variable a, because we declared it. Yes, we declared it later, but we declared it.
The second line creates an implicit global variable b, because we never declared b anywhere in foo.
More (on my blog):
Poor, misunderstood var
ES2015 (aka "ES6") introduced let and const. They're handled slightly differently from var:
They have block scope rather than function or global scope.
The declaration is hoisted to the top of the block, but they don't get any default value at that point; they get initialized (with undefined or the value you provide) only when the declaration is reached in the step-by-step execution of the code.
Demonstrating point #1 (block scope):
function foo() {
{
let a = 1;
console.log(a); // 1
}
console.log(a); // ReferenceError: a is not defined
}
foo();
Demonstrating point #2: This would work with var, it doesn't work with let:
function foo() {
a = 42; // ReferenceError: a is not defined
let a;
}
foo();
The time between when the identifier is reserved (declaration) and when you can use it (initialization) is called the Temporal Dead Zone within which you can't use the variable.
Javascript Engine will execute code in two phases
Pre processing phase(or instantiation phase).
Execution Phase.
Pre processing phase(or instantiation phase)-
In Preprocessing phase, the script is scanned completely for all the declarations.
var - is the identifier to declare a variable.
So when var identifier is encountered, variable will be declared in the global scope.
The value of the variable is - undefined
Execution Phase-
In Execution Phase, the script is executed line by line. All the initializations will be done in this phase.
Example-1
For Below code snippet,
In Pre processing phase, Javascript engine will scan through the code line by line, when it encounters line "var a", it will declare variable a in the global scope.
In the Execution phase, at line "a=10", variable 'a' will be initialized with value 10. when it encounters console statements, value 10 will be printed.
a=10;
console.log(a); // 10
var a;
console.log(a); // 10
This is how variable hoisting works.
In Javascript, var x = 21; is broken into 2 parts: var x; and x = 21;.
The var x; part is always hoisted to the beginning of the enclosing function. The x = 21; part is left in its original place.
The same thing happens with function () {} declarations - this would be hoisted to the top of the enclosing function scope:
function pie () {
return 21;
}
just like the var.
A variable can be used before it is declared
JavaScript Initializations are Not Hoisted
Function Hoisting
As previously mentioned, function declarations are also hoisted. However, functions that are assigned to variables are not hoisted.
See below example
Function Declaration Overrides Variable Declaration When Hoisted
Shouldn't the value of research be undefined as it has been declared as var research in the end. And hence the output be a type error. But I am getting the output as 'hello'. Any idea why?
function newFunc() {
function research() { console.log('hello') };
research();
var research;
}
newFunc();
Because of hoisting, what actually happens is more like this:
function newFunc() {
var research;
research = function() { console.log('hello') };
research();
}
newFunc();
The variable declarations and function definitions are hoisted - moved to the top of the function scope. So even though you are declaring it at the end, the compiler will move it to the top of the function so it ends up like:
function newFunc() {
var research = function () { console.log('hello') };
research();
}
newFunc();
JS only hoists declarations, not initializations. JS also hoists the actual function definition.
JavaScript only hoists declarations, not initializations. Documentation
So values will be assigned in the order they are placed, for instance:
x = 2;
console.log(x); //2
x = 3;
console.log(x); //3
var x ;
or in your case:
var x = 2;
console.log(x); //2
var x = 3;
console.log(x); //3
var x ;
Another thing is that, research in the var research; part is not undefined; it's rather a function expression till you override it by another assignment, like var research = '';
So in your case, it's like the following:
function newFunc() {
function research() { console.log('hello') };
research(); //'hello'
var research;
console.log(research) //function research(){console.log('hello');}
}
When hoisting is occurring to the variable which declaring with keyword var inside an if block scope, does the ( var x;) hoisting to the top of current if block? or to the top of the global scope in this case?
Suppose we wrote the following piece of code directly in the global scope
if (true) {
some code;
var x = 1;
}
When using var (or omitting the definition key at all e.g just x = 1) as per your example, it would be hoisted to the closest scope which in your example would be the global scope (window).
If it would be wrapped in a function, then the function would be the closest scope.
function a() {
if(true){
var x=1;
}
console.log(x) // 1
console.log(window.x) // undefined
}
a()
console.log(x) // Throws error (x is not defined)
If you want the variable to be completely block scope, then you would need to use let or const.
if(true){
const x=1;
}
console.log(x) // Throws error (x is not defined)
Absolutely.
// hoisted
if( true){
x = 1;
console.log( x, typeof x );
var x;
}
// doesn't do what you thought it would, the assignment doesn't move, just the declaration.
if( true){
console.log( y, typeof y );
var y = 1;
}
The short answer is that yes, the declaration is hoisted but not to the top of the block. It is hoisted to the global level. But where it is assigned does not change.
This is tricky to test because an undeclared variable and a declared variable will both produce a typeof somevar of undefined.
var myVar;
console.log('typeof myVar');
console.log(typeof myVar);
console.log('typeof notDeclared');
console.log(typeof notDeclared);
However, if you try to use an defined variable it will throw an error, so we can use that to find out what has been declared and what has not.
var myVar;
try {
myVar;
console.log('myVar was declared');
} catch(error) {
console.log(error);
}
try {
notDeclared;
console.log('notDeclared was declared');
} catch(error) {
// Error is unfortunately captured by the sandbox,
// so we just get an empty object. :-(
console.log(error);
}
Putting it all together, we can test your code to see what happens.
// Does myVar exist in global scope?
try {
myVar;
console.log('myVar exists in global scope.');
} catch (error) {
console.log('myVar does NOT exist in global scope.');
}
if (true) {
console.log('myVar value before assignment.', myVar);
var myVar = 1;
console.log('myVar value after assignment.', myVar);
}
I was practicing some scenario and find a case:
Here is fiddle
According to closure bar function should have access to var x so I expected to alert 1 and condition get false due to if(!1) but it alerted undefined and condition get true and second alert is with value 10.
var x = 1;
function bar() {
alert(x);
if (!x) {
var x = 10;
}
alert(x);
}
bar();
So I am confused why it is prompting undefined?
According to hoisting in a particular scope you define a variable anywhere it is considered as defined at top always.
If it is due to hoisting effect it still have to alert 10 instead of undefined.
Hoisting causes a variable to be declared everywhere in the function, not defined.
On the first line of bar, since there is var x on line 3 of the function, the global x is masked and you see the local x (which is undefined since it hasn't been given a value yet).
On line 3 of bar, you have x = 10 which defines the variable. This is not hoisted.
On line 5, you alert it, and it is now defined.
Hoisting will make your code effectively work like this:
var x;
x = 1;
function bar() {
var x; //same as var x = undefined;
alert(x);
if (!x) {
x = 10;
}
alert(x);
}
bar();
var x = 3;
(function (){
console.log('before', x);
var x = 7;
console.log('after', x);
return ;
})();
In the above code var X is initialized globally. So inside the function the first console.log should print "before 3" but i don't get it. The reason is that i am trying to re-declare the global variable.
Can somebody explain why this is happening?
In the above code var X is initialized globally. so inside the function the first console.log should print "before 3".
No, it should print before undefined, because var takes effect from the beginning of the function regardless of where you write it.
Your code is exactly the same as this:
var x = 3;
(function (){
var x;
console.log('before', x);
x = 7;
console.log('after', x);
return ;
})();
And of course, variables start with the value undefined.
Details: Poor misunderstood var
The JavaScript parser does Variable Hoisting when parsing your code. This means that any variable declaration will be moved to the top of the current scope, thus in your case, this code will get executed:
var x = 3;
(function (){
var x;
console.log('before', x);
x = 7;
console.log('after', x);
return ;
})();
So your local variable x gets declared at first with an initial value of undefined.
This should explain, why you get an "beforeundefined" for the first console.log().
The scope of a variable is much simpler than in other languages. It doesn't start at declaration but is either :
the function in which you have the declaration
the global scope if the declaration isn't in a function
MDN :
The scope of a variable declared with var is the enclosing function
or, for variables declared outside a function, the global scope (which
is bound to the global object).
You can imagine that all variable declarations are moved to the start of the scope (the function). So this is exactly like
var x = 3;
(function (){
var x;
console.log('before', x); // now undefined
x = 7;
console.log('after', x); // now 7
return ;
})();
Be careful to understand what is the exact scope (the function, not the block) :
var x = 3;
(function (){
console.log('before', x); // this is undefined !
if (true) {
var x = 7;
}
return ;
})();