I was trying to understand JavaScript hoisting and from what I have understood, memory space is set aside for all the variable declarations before the execution of the code.
I would like to understand how the interpreter works through hoisting in case of multiple declarations for the same variable. Consider the following code:
console.log(a);
//first declaration
function a() {
console.log('hello');
}
//second declaration
var a = 2;
The output is the function declaration:
function a() {
console.log('hello');
}
So, I am assuming the first declaration the interpreter encounters is the one which is stored in memory. However, changing the order of declarations to:
console.log(a);
//first declaration
var a = 2;
//second declaration
function a() {
console.log('hello');
}
results in the same output! The interpreter ignores the first declaration and stores the second declaration in memory. Why is this happening? Shouldn't the output in the second case be undefined?
Your code will be read by the interpreter like below,
function a() {
console.log('hello');
}
var a;
console.log(a);
a = 2;
so while executing the above code, a will be referring the function initially and after that var a; line will be executed, since a is undefined there, an assigned value will not be set with undefined by means of a variable declaration. Hence that line got ignored and printing the primitive value of the function reference.
A simple example for your better understanding would be,
function x(){ };
var x;
console.log(x); //function x(){ }
Related
I am having trouble understanding why the following code prints 1 and not 10. I thought that console.log would print 10 because if a variable is not declared within a function it is part of the global scope.
If I remove the line, function a(){}, the console.log statement prints 10. Can someone please explain why the presence of this line affects the value of a.
Additionally, if this question can be refined I would appreciate any suggestions
function b() {
a = 10;
return;
function a(){}
}
var a = 1;
b();
console.log(a);
Just add console.log(a); to your function and you will realize that 'a' is a function that has local scope, which means, it inside function b() and can't really be called from outside. Hence, the value of a remains as 1, as nothing really affects it.
function b() {
console.log(a);
a = 10;
return;
function a(){}
}
var a = 1;
b();
console.log(a);
Function declarations create local variables, and all declared variables are hoisted to the top of their containing function scope. Thus, you have something equivalent to:
function b() {
function a(){}
a = 10;
return;
}
which is in turn roughly equivalent to
function b() {
var a = function(){}
a = 10;
return;
}
As you can see in this form, it's clear that a is a local variable, so a = 10 assigns a value to the local a, not the global a.
Because both function declarations and variables are treated similarly under the hood.
When a function is called, its contents are first parsed to configure the stack frame ready for its execution.
As part of this process, function declarations and variables are inserted as identifier/value pairs into the same data structure (Environment Record inside the Lexical Environment) inside the stack frame (Execution Context) created when a function is called.
So by declaring a function a inside b, you create an identifier named "a" in the Environment Record created for the call to b, shadowing a in the outer context.
So a in the outer context remains 1.
I have the following code, where I declare a function and after it, a variable with the same name as the function:
function a(x) {
return x * 2;
}
var a;
alert(a);
I expected this to alert undefined, but if I run it, the alert will display the following:
function a(x) {
return x * 2
}
If I assign a value to the variable (like var a = 4), the alert will display that value (4), but without this change a will be recognized as a function.
Why is this happening?
Functions are a type of object which are a type of value.
Values can be stored in variables (and properties, and passed as arguments to functions, etc).
A function declaration:
Creates a named function
Creates a variable in the current scope with the same name as the function (unless such a variable already exists)
Assigns the function to that variable
Is hoisted
A var statement:
Creates a variable in the current scope with the specified name (unless such a variable already exists)
Is hoisted
Doesn't assign a value to that variable (unless combined with an assignment operator)
Both your declaration and var statement are hoisted. Only one of them assigns a value to the variable a.
In JavaScript both function declaration and variable declarations are hoisted to the top of the function, if defined in a function, or the top of the global context, if outside a function. And function declaration takes precedence over variable declarations (but not over variable assignment).
Function Declaration Overrides Variable Declaration When Hoisted
First you declare a variable:
var a; // value of a is undefined
Second, the value of a is a function because function declaration takes precedence over variable declarations (but not over variable assignment):
function a(x) {
return x * 2;
}
And that is what you get when you call alert(a);.
But, if instead of declaring a variable you make variable assignment: var a = 4; then the assigned value 4 will prevail.
If you use a function name as variable name, its value is replaced by function body. So var a becomes your function a and thus your alert displays function a.
Edit But if you assign value to a like var a = "xya";. Then it function will be replaced by variable. As per Order of precedence
Variable assignment takes precedence over function declaration
Function declarations take precedence over variable declarations
You should also remember that var a is hoisted, which makes it more like this
var a; // placed
function a(x) {
return x * 2;
};
var a; // removed
alert (a); // a is replaced by function body
Remember that var a is hoisted, so if you assign 4 to a:
var a; // placed
function a(x) {
return x * 2;
};
var a = 4; // removed
a = 4 // added
alert (a); // a is now 4
First hoisting takes place. Function declaration takes precedence over variable declaration during hoisting.
During execution of the code, if variable is assigned at any point, then it is replaced, otherwise it remains the same function.
(Note: First read the code from Line 4 to Line 8. Then again read from beginning to end.)
console.log(a); // f a(){...} - Executed just after hoisting
console.log(b); // f b(){...} - Executed just after hoisting
var a = 100; // here variable is assigned
function a(x) {...};
function b(x) {...};
var b; // only a declaration here
console.log(a); // 100
console.log(b); // f b(){...}
ES6 comes with a better solution by defining SyntaxError: Identifier (?) has already been declared when using let / const instead of var.
let
function foo () {}
let foo;
// => SyntaxError: Identifier 'foo' has already been declared
const
function foo () {}
const foo = 1;
// => SyntaxError: Identifier 'foo' has already been declared
Note that const foo; does not work. It will cause SyntaxError: Missing initializer in const declaration
This question already has answers here:
Why is my global variable shadowed before the local declaration?
(3 answers)
Closed 9 years ago.
I'm modifying a piece of code in 3 ways. In these 3 conditions in is behaving differently. Please describe how it's executing?
var a=1;
function myFunc(){
console.log(a);
console.log(a)
}
myFunc();
//Output is:
1
1
var a=1;
function myFunc(){
console.log(a);
var a=2;
console.log(a)
}
myFunc();
//Output is:
undefined
2
var a=1;
function myFunc(){
console.log(a);
var a=2;
console.log(a)
}
myFunc(a);
//Output is:
undefined
2
Why in 2nd case it's printing undefined? And in 3rd case I'm sending my global a as an argument, then also it's printing undefined.
That's because JavaScript moves var declarations to the top of the scope, so your code actually is:
var a = 1;
function myFunc(){
var a; // a is redeclared, but no value is assigned
console.log(a); // therefore it evaluates to undefined
a = 2; // now a = 2
console.log(a); // and then it logs to 2
}
myFunc();
This behaviour is called Variable Hoisting.
EDIT
As Beterraba said, in the third code it logs undefined because no argument was declared in the function's header:
var a = 1;
function myFunc(a) { // a is declared
console.log(a); // now a logs 1
var a = 2; // now a = 2
console.log(a);
}
myFunc(a);
The second case is printing undefined due to the way that JavaScript Execution context works. You might have come across the term hoisting.
To explain it in more details, when the second function is invoked, the interpreter will enter a process with two phases.
Creation stage
Creates the scope chain
Creates arguments, functions, variables, the so-called variable object
Determines the value of "this" keyword
Activation or code execution stage
interprets and executes the code
So when you callmyFunc() the JavaScript interpreter will create an execution context which you can think of as an object literal that looks like this:
myFuncExecutionContext = {
scopeChain: { ... },
variableObject: {
arguments: {
length: 0
},
a: undefined,
},
this: { ... }
}
You can see that the local a variable has an initial value of undefined. During the code execution stage, the interpreter will run the function line by line; So the first line it sees is the console.log(a);. The interpreter will look at the variableObject to see if there is variable with that name. If not it will use the scope chain and will try to locate it in the variable object of the outer scopes. Since, there is the a variable in the variable object, it will read it's value, which is undefined.
Then it will do to line 2 where it will assign a value to the local variable a; var a=2;. Then it will execute the last line - console.log(a) - which will print the value that we assigned earlier.
The same mechanism justifies why we can invoke a function before it's defined, as long as, we use a function declaration syntax.
someFunc(); // VALID
function someFunc(){ };
Whereas the following will cause an error:
someFunc(); // TypeError: undefined is not a function
var someFunc = function() { }
<script type="text/javascript">
var output = function() {console.log('result')}
output();
</script>
If I changed to output = function() {console.log('result')}; it still shows the right result, so my question is:
what is the difference between them? when should I put var in front of function in js? is that the same principle as var in front of variable?
A function defined in a script tag is in the global scope (ie the window object in a browser context) so there is no difference in this case.
Inside a function block, however, is a different story. For example:
foo = function() {
var foo = 1;
console.log(foo);
}
foo(); // logs '1'
foo(); // logs '1'
But:
foo = function() {
foo = 1;
console.log(foo);
}
foo(); // logs '1'
foo(); // SyntaxError: Unexpected token function
Because foo wasn't defined locally, we overwrote the global object.
You're in the global window scope, so there's no difference.
It doesn't matter what the type of the variable is.
If this is declared in functions, then there is a difference:
function name(){
var a=1;
}
alert(a);
Here a will be undefined, as var declares the variable in the scope of the function.
As an excercise:
var a=2;
function name(){
var a=1;
}
name();
alert(a);
This alerts 2 instead of 1, since the middle var belongs in the scope of the function, which is separate from the global scope.
You can also modify global variables this way:
var a=2;
function name(){
a=3;
}
name();
alert(a);
Also compare this with let, which limits it's scope to the block instead: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
"Is that the same principle as var in front of variable?"
Yes. output is a variable.
So I would suggest you use var in front of it when you define it. You could eventually change its value without using var. As in:
var A=1;
A=2;
A=A+1;
Consider the "script" of the funcion as the "value" of that variable.
var F=function() {console.log('one')};
// change it later
F=function() {console.log('two')};
(not suggesting you do this, but to show you it is 100% a var)
You are actually assigning to the variable named "output" a value of "function() {console.log('result')}" not as a string but as a script that gets executed. Note the semicolon at the end like in var A=3;
Now "inside" output there is the code that executes console.log('result'). (more or less, just to explain).
As you usually do not change that same function later (you can, and sometimes it is done) I really suggest you use var in front of it every time you define a function like this, even in cases when it is not strictly necessary, just to be safe you do not override an existing function.
This is a bit different from defining the function as:
function output() {console.log('result')}
Here there is no = sign, no assignment, no semicolon at the end. This is not a variable assignment but a function "definition" although results are similar, and you can call output() in both cases, there are differences. The main one I think is that function definitions are examined before executing the script line by line, while with assignment you really need to have the assignment line processed before you can use the function. So this:
output();
function output() {console.log('result')}
works. While this:
output(); // nope! output not defined yet!
var output=function() {console.log('result')}
doesn't. Variables are assigned or changed when the assignment instruction is read and interpreted.
// here A is undefined, B() prints 'ok'
var A=function() {console.log('first')};
// here A() prints 'first', B() prints 'ok' as usual
A=function() {console.log('second')}; // change it
// here A() prints 'second', B() prints 'ok' as usual
function B() {console.log('ok')}
// same here A() prints 'second', B() prints 'ok'
Without var your variable will be declared as global variable which means it is available on other JS files too. In short If you declare a variable, without using var, the variable always becomes GLOBAL.
Generally there is no difference because you are in the global scope, but in ES5 there's a strict mode, which slightly changes the behavior of undeclared variables. In strict mode, assignment to an undeclared identifier (not putting var in front) is a ReferenceError.
For example:
"use strict";
myVariable = "foo"; // throws a ReferenceError
Function or not function, here's what MDN has to say about var:
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).
Using var outside a function is optional; assigning a value to an undeclared variable implicitly declares it as a global variable (it is now a property of the global object). The difference is that a declared variable is a non-configurable property of the global object while an undeclared is configurable.
And you could also read about the function statement here and the function operator here.
Cheers!
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