The following test is a success, and prints 1 and 1:
function test1() {
a = 1;
console.log(a); // prints "1"
}
function test2() {
console.log(a); // prints "1"
}
test1();
test2();
And the following test fails, because a local variable overrides the previously created global one:
function test1() {
a = 1;
var a = 2;
console.log(a); // prints "2"
}
function test2() {
console.log(a); // throws an error
}
test1();
test2();
Why does the second example remove the global variable permanently? What purpose/logic does such functionality serve in JavaScript?
EDITED: For those who marked it as a duplicate of Strange Behavior on Global and Local Variable in JavaScript
Hoisting refers to the scenario when a later declared local variable is moved up the function scope, overriding the previously visible variable. But in our case the function first creates a global variable, and then deletes it completely/globally.
However, it is probably related, as we can see in the following test:
function test1() {
a = 1;
console.log(a); // prints "1"
}
function test2() {
console.log(a); // prints "undefined"
var a = 2;
}
function test3() {
console.log(a); // prints "1"
}
test1();
test2();
test3();
In your second case, no global variable named a ever exists.
a = 1 generally does not create a global variable. The statement a = 1 stores the value 1 in a variable called a. If the variable environment of any containing local scope has a variable called a, the nearest scope with an a variable will have that variable set to 1.
As a special case, if a variable called a does not exist in any containing scope (and if you are not in strict mode), then the JavaScript engine will create a global variable called a.
In your second case, var a creates an a variable in the local scope. Due to hoisting, that modification to the scope's variable environment happens before any code runs. Thus, by the time a = 1 is executed, that local scope does have a variable called a, so that local variable is used.
In your third case, test2 logs the local variable a (created by the var a). At the time the log call is made, the local a has not yet been assigned a value.
Hoisting refers to the scenario when a later declared local variable is moved up the function scope, overriding the previously visible variable.
Hoisting simply means that all var declarations are treated as if they happen at the top of their containing function. It has nothing to do (directly) with overriding variable visibility.
Note that declarations with an assignment will have only the declaration hoisted, not the assignment. The assignment stays in place wherever it is in the function.
Javascript moves variable declarations to the top. So in this example the compiler reads you code as:
function test1() {
var a;
a = 1;
a = 2;
console.log(a); // prints "2"
}
function test2() {
console.log(a); // throws an error
}
test1();
test2();
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
Currently I am getting the result undefined and I don't understand why that is.
var variable = "top-level";
function parentFunction() {
function childFunction() {
alert(variable);
}
childFunction();
var variable = "local";
}
parentFunction();
I thought that because I declared the variable
var variable = "local";
after I called childFunction(), it would look up the scope chain and get the top level variable instead, but it seems that this isn't the case.
That happens because of hoisting, which is putting all var statements at the top of the function, but still executes the assignment statement at the line it was made. If you have a look below, the second var variable will shadow the global variable since it declares a local variable with the same name. Then, this newly declared variable will be undefined until it reaches the assignment line.
Basically, here's what your code does:
var variable = "top-level";
function parentFunction() {
var variable;
function childFunction() {
alert(variable);
}
childFunction();
variable = 'local';
}
parentFunction();
All the variable declaration statements will be moved to the top of the function in which they are declared, but the values will be assigned to them only when the control reaches the declaration/initialization statement. In your case, childFunction doesn't have variable, so it goes up in the scope and checks the parentFunction, where variable is declared but not assigned a value yet. So, it alerts the default value undefined.
This is called variable hoisting.
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!