This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 6 years ago.
Hi I am trying to understand the JavaScript fundamentals, and stuck in one condition.
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
Here alert(foo), will give me 1, and I know after return statement, function foo() will not execute. But now if change the code:
var foo = 1;
function bar(){
foo = 10;
return;
}
bar();
alert(foo);
In bar function, If I will remove function foo(). then alert(foo) will give me 10
Please help, if someone can explain me why?
This is called Javascript hoisting
I will try to explain it in details.. This is what we have
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
The interpreter will rewrite this as
var foo = 1;
function bar(){
function foo(){} // this is also equal to var foo = function(){};
foo = 10;
return;
}
bar();
alert(foo);
So now explaining you the hoisted code.
var foo = 1; // global variable;
function bar(){
var foo = function(){}; // foo is local variable of type function
foo = 10; // foo is changed to hold a number
return;
}
bar();
alert(foo); // you alert global variable.
As you can see if the code function foo(){} is present it is treated as a local variable within the bar() scope and any change to the foo is treated as a local variable change..
When you have function foo(){} in your bar() you are not even touching the global variable.. hence alerts 1.
When you don't have function foo(){} you are touching the global variable and hence alerts 10.
Now I hope you understand the output..
I know after return statement ,function foo() will not execute.
That's not true.
Function declarations are hoisted.
function foo(){} creates a local variable called foo (assigning the new function to it) and then foo = 10 overwrites it. You never test the value of that foo variable though.
In bar function , If I will remove function foo(). then alert(foo) will give me 10
You no longer have a local variable called foo so you are overwriting the global variable with the same name.
Compare:
(function() {
console.log("Version 1");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
function foo() {}
}
bar();
console.log("Global foo is " + foo);
}());
(function() {
console.log("Version 2");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
}
bar();
console.log("Global foo is " + foo);
}());
When you write this function :
function bar(){
foo = 10;
return;
function foo(){}
}
The javascript read this :
function bar(){
function foo(){}
foo = 10;
return;
}
The function foo is created into your local function bar. And when you write foo = 10,You overwrite the function foo in the local scope and not the global variable.
So your alert give you 1 because you never update the global variabe.
The problems here are hoisting and closure .
The declaration function foo(){} is hoisted, meaning in this case, even though it is written at the end of the function, it will be available everywhere within the scope, including before it's definition.
if function foo(){} IS NOT present, the statement foo = 10; overwrites the foo defined in the global scope. Therefore the global foo === 10.
If function foo(){} IS present, the statement foo = 10; just overwrites the function foo in the local scope, the global foo won't get touched hence global foo === 1
var foo = 1;
function bar(){
console.log(typeof foo) // function
return;
function foo() {}
}
bar();
alert(foo);
Opposed to:
var foo = 1;
function bar(){
console.log(typeof foo) // number
return;
// function foo() {}
}
bar();
alert(foo);
So basically what is happening is as if you have declared var foo = 10
because function declaration in javascript are hoisted up top
complier sees your code as follows .
var foo = 1;
function bar(){
var foo;
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
so in fact foo = 10 never overwrites the global foo;
it is kept local to the function .
so alert will get passed the global one .
In addition to my previous answer in the same thread I am
adding another answer to put in more details about the Hoisting
feature in JavaScript as the previous answer is already accepted by the OP for its content.
First lets get comfortable with what scoping is
Scoping in JavaScript
One of the sources of most confusion for JavaScript beginners is scoping. Actually, it’s not just beginners. I’ve met a lot of experienced JavaScript programmers who don’t fully understand scoping. The reason scoping is so confusing in JavaScript is because it looks like a C-family language. Consider the following C program:
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
The output from this program will be 1, 2, 1. This is because C, and the rest of the C family, has block-level scope. When control enters a block, such as the if statement, new variables can be declared within that scope, without affecting the outer scope. This is not the case in JavaScript. Try the following in Firebug:
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
In this case, Firebug will show 1, 2, 2. This is because JavaScript has function-level scope. This is radically different from the C family. Blocks, such as if statements, do not create a new scope. Only functions create a new scope.
To a lot of programmers who are used to languages like C, C++, C#, or Java, this is unexpected and unwelcome. Luckily, because of the flexibility of JavaScript functions, there is a workaround. If you must create temporary scopes within a function, do the following:
function foo() {
var x = 1;
if (x) {
(function () {
var x = 2;
// some other code
}());
}
// x is still 1.
}
This method is actually quite flexible, and can be used anywhere you need a temporary scope, not just within block statements. However, I strongly recommend that you take the time to really understand and appreciate JavaScript scoping. It’s quite powerful, and one of my favorite features of the language. If you understand scoping, hoisting will make a lot more sense to you.
Declarations, Names, and Hoisting
In JavaScript, a name enters a scope in one of four basic ways:
Language-defined: All scopes are, by default, given the names this and arguments.
Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
Function declarations: These are of the form function foo() {}.
Variable declarations: These take the form var foo;.
Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter.
Function parameters and language-defined names are, obviously, already there. This means that code like this:
Ex:
function foo() {
bar();
var x = 1;
}
is actually interpreted like this:
function foo() {
var x;
bar();
x = 1;
}
It turns out that it doesn’t matter whether the line that contains the declaration would ever be executed. The following two functions are equivalent:
function foo() {
if (false) {
var x = 1;
}
return;
var y = 1;
}
function foo() {
var x, y;
if (false) {
x = 1;
}
return;
y = 1;
}
Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted. This is not the case with function declarations, where the entire function body will be hoisted as well. But remember that there are two normal ways to declare functions. Consider the following JavaScript:
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
}
test();
In this case, only the function declaration has its body hoisted to the top. The name ‘foo’ is hoisted, but the body is left behind, to be assigned during execution.
That covers the basics of hoisting. The complete 100% credit of this answer goes to ben cherry. I didnt want to post this link in my answer because the links might break and I found this completely informative and a must read for any javascript developer.
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
For example:
(function foo() {
var a = 3;
console.log(a);
});
var obj = {
a: (function foo() {
var a = 2;
console.log(a);
})
};
obj.a(); // 2
foo(); // ReferenceError: Not Defined
How is that I can access a function expression within obj, but not in the global object?
Edits: for cohesion and clarity
You're confusing a couple of different things here.
Your first statement is a function expression, not a function declaration:
(function foo() {
var a = 3;
console.log(a);
});
This happens to be a named function expression ("foo"), but it does not introduce a variable foo in this scope. If you wanted to introduce foo so that it can be called again, you need either a function declaration...
function foo() {
var a = 3;
console.log(a);
}
foo();
or, you need to assign the function expression to a variable:
var foo = function () {
var a = 3;
console.log(a);
}
foo();
Your next bit of code, the object declaration, effectively does this by assigning the function expression to a variable, obj.a:
var obj = {
a: (function foo() {
var a = 2;
console.log(a);
})
};
The error in your thinking here is due to confusion around foo. In both cases, foo is the name of the function, but it's not actually relevant to invoking the function. You should drop the foo because it's only confusing things.
In essence, your first snippet is equivalent to:
(function () { alert('x'); });
This line of code defines an anonymous function, but does nothing with it. The function exists briefly, is never invoked, and then is lost, because it is not assigned to anything.
Your second snippet is equivalent to:
var x = function () { alert('y') };
This code defines a variable, x, and assigns a function to it. The function can then be invoked with x(), and the function remains available as long as x is in scope.
Your original question is:
How can an object access function expression?
Which doesn't really make sense. The object can't "access the function expression", it just contains a property to which a function has been assigned, while the snippet outside the object did not retain the function in a way that would allow you to invoke it.
I have a variable named foo and function named foo.
//variable followed by function declaration
var foo="bar";
function foo(){
return "bar";
}
//function declaration followed by variable
function foo(){
return "bar";
}
var foo="bar";
//When I call foo it returns string bar;
//When I enquired foo() it throws error
What's happening here?Why does the variable name override function declaration?
When I call foo it returns string bar;
Function declarations are hoisted to the top of their scope. The function definition are moved above by the compiler. And then the variable is overwriting to string.
Code is equivalent as
function foo() {
return "bar";
}
// Overwriting the value
var foo = "bar"
So, in both the cases, the output will be 'bar'.
Note that function expressions are not hoisted.
For more information on function hoisting, see Javascript function scoping and hoisting
When I enquired foo() it is undefined
foo here is not a function, it's a string. So, foo() will throw an error
Uncaught TypeError: a is not a function(…)
In a clearer and more explicit way of declaring variables, the latter will take account:
var foo = "bar";
var foo = function () {
return "bar";
};
console.log(foo);
output is a function
and the reversal:
var foo = function () {
return "bar";
};
var foo = "bar";
console.log(foo);
has "bar" as output.
In JavaScript, functions are processed upon entering the corresponding scope.
The variables are processed when the interpreter gets to their declaration.
Therefore in your example, the functions are processed first, the name foo is used by the last function and then overwritten by the variables.
Note that if you declare your function like this
var foo = function() {}
it is actually not processed at the beginning and also overwriting the variables declared beforehand.
var foo="bar";
var foo = function(){
return "bar";
};
They are the same. Don't miss to put ; in the end of line.
both cases will return the string "bar"
basically javascript grabs all functions and put them in the top of the file
its called hoisting .
so the string declaration will overwrite the function expression in both cases ;
This is a simple snippet, I just dont understand something.
The below code outputs 12, I understand that, because the var foo = 12; replaces the previous declaration of the variable.
<script>
var foo = 1;
function bar(){
if (!foo) {
var foo = 12;
}
alert(foo);
}
bar();
</script>
In the below code, it alerts 1 , which means the variable declared outside the function is accessible inside the function.
<script>
var foo = 1;
function bar(){
alert(foo);
}
bar();
</script>
But, in the below code, why it alerts undefined ?? I thought, it will alert 1, I am just assigning the previously declared variable to the new one.
<script>
var foo = 1;
function bar(){
if (!foo) {
var foo = foo;
}
alert(foo);
}
bar();
</script>
Variable declarations are pushed to the start of the function.
Therefore in reality the following is happening:
function bar(){
var foo;
if (!foo) {
foo = foo;
}
alert(foo);
}
Therefore you would need to change this to use window.foo so that you're referring to the global property rather than the function's property:
var foo = 1;
function bar(){
var foo;
if (!window.foo) {
foo = window.foo;
}
alert(foo);
}
bar();
Hoisting is slightly tricky. Function declarations are hoisted with the function assignment, but variable declarations are hoisted without the variable assignment. So the execution order of code is actually:
var foo;
var bar = function bar(){
var foo; // undefined
if (!foo) { // true
foo = foo; // foo = undefined
}
alert(foo);
}
foo = 1;
bar();
You could either use window.foo if you want to refer to the global variable foo, or better, just use a different variable name:
var foo = 1;
function bar(){
var baz = foo;
alert(baz);
}
bar();
The below code outputs 12, I understand that, because the var foo =
12; replaces the previous declaration of the variable.
var foo = 1;
function bar(){
if (!foo) {
var foo = 12;
}
alert(foo);
}
bar();
You are right because local variable overriding the global one.
In the below code, it alerts 1 , which means the variable declared
outside the function is accessible inside the function.
var foo = 1;
function bar(){
alert(foo);
}
bar();
You are correct. foo is declare in global scope so is accessible fron anywhere.
But, in the below code, why it alerts undefined ?? I thought, it will
alert 1, I am just assigning the previously declared variable to the
new one.
var foo = 1;
function bar(){
if (!foo) {
var foo = foo;
}
alert(foo);
}
bar();
This is a bit different. You are declaring a global variable and a local one with the same name. When your JavaScript program execution enters a new function, all the variables declared anywhere in the function are moved (or elevated, or hoisted) to the top of the function.
Another example:
var a = 123;
function f() {
var a; // same as: var a = undefined;
alert(a); // undefined
a = 1;
alert(a); // 1
}
f();
In javascript, until the ES5 specification, the scope is implemented only in terms of function body. The concept of block scope doesn't exist (really, will be implemented in the next javascript with the let keyword).
So, if you declare a variable var something; outside from function body, it will be global (in browsers global scope is the scope of the window object).
global variables
var something = 'Hi Man';
/**
* this is equal to:
**/
window.something = 'Hi Man';
If your code doesn't run in strict mode, there is another way to declare a global variable: omitting the var keyword. When the var keyword is omitted the variable belongs (or is moved) to the global scope.
example:
something = 'Hi Man';
/**
* this is equal to:
**/
function someFunction() {
something = 'Hi Man';
}
Local Variables
Because the non-existence of block scopes the only way to declare a local variable is to define it in a function body.
Example
var something = 'Hi Man'; //global
console.log('globalVariable', something);
function someFunction() {
var something = 'Hi Woman';
console.log('localVariable', something);
/**
* defining variable that doesn't exists in global scope
**/
var localSomething = 'Hi People';
console.log('another local variable', localSomething);
}
someFunction();
console.log('globalVariable after function execution', something);
try {
console.log('try to access a local variable from global scope', localSomething);
} catch(e) { console.error(e); }
As you can see in this example, local variables don't exist outside from their scope. This means another thing... If you declare, with the var keyword, the same variable in two different scopes you'll get two different variables not an override of the same variable (name) defined in the parent scope.
If you want to "override" the same variable in a child scope you have to use it without the var keyword. Because of the scope chain if a variable dosn't exist in a local scope it will be searched on their parent scope.
Example
function someFunction() {
something = 'Hi Woman';
}
var something = 'Hi Man';
console.log(1, 'something is', something);
someFunction();
console.log(1, 'something is', something);
Last thing, variable hoistment.
As I wrote below, at the moment, there isn't any way to declare a variable in some point of your code. It is always declared at the start of it scope.
Example
function someFunction() {
// doing something
// doing something else
var something = 'Hi Man';
}
/**
* Probably you expect that the something variable will be defined after the 'doing
* something else' task, but, as javascript works, it will be defined on top of it scope.
* So, the below snippet is equal to:
**/
function someFunction1() {
var something;
// doing something
// doing something else
something = 'Hi Man';
}
/**
* You can try these following examples:
*
* In the someFunction2 we try to access on a non-defined variable and this throws an
* error.
*
* In the someFunction3, instead, we don't get any error because the variable that we expect to define later will be hoisted and defined at the top, so, the log is a simple undefined log.
**/
function someFunction2() {
console.log(something);
};
function someFunction3() {
console.log('before declaration', something);
var something = 'Hi Man';
console.log('after declaration', something);
}
This happens because in javascript there are two different steps of a variable declaration:
Definition
Initialization
And the function3 example becomes as following:
function3Explained() {
var something; // define it as undefined, this is the same as doing var something = undefined;
// doing something;
// doing something else;
something = 'Hi Man';
}
IMHO it doesn't have anything to do with function declaration and hoisting ,
declaring the var with var inside function you are creating a variable in the function's isolated scope, this is why you get undefined.
var foo = 1;
function funcOne() {
var foo = foo;
alert('foo is ' + foo);
};
funcOne();
var bau = 1;
function funcTwo() {
bau = bau;
alert('bau is ' + bau);
};
funcTwo();
fiddle
One of my friends was taking an online quiz and he asked me this question which I could not answer.
var global = false;
function test() {
global = true;
return false;
function global() {}
}
console.log(global); // says false (As expected)
test();
console.log(global); // says false (Unexpected: should be true)
If we assume that functions are hoisted at the top along with var variables, let's try this one.
var foo = 1;
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
Here is a JSBin Demo and JSBIN Demo2 to play with.
PS: If we remove function global() {} from test(), then it runs fine. Can somebody help me understand why is this happening ?
var statements and function declaration statements are "hoisted" to the top of their enclosing scope.
Therefore, the function global(){} in your function creates a local global name.
Assigning to global inside your functions binds to this local name. Here's how you can "rewrite" it using hoisting to understand how the compiler sees it:
function test() {
var global = function() {}; // hoisted; 'global' now local
global = true;
return false;
}
I'll answer the second part of your question,
If we assume that functions are hoisted at the top along with var variables
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
You should try console.log(bar()); console.log(foo); instead. However, what hoisting does to your function is this:
function bar() {
var foo;
function foo() {}
return foo;
foo = 10;
foo = 11;
}
So you should expect to get the function returned, since your variable assignments are after the return statement. And both the var and the function declaration make foo a local variable, so the global foo = 1 is never changed.