Im new to Javascript and I dont understand whats happening how the scope works in the following codes:
//Code n°1:
let num = 1;
function test(){
console.log(num);
}
test() //As I expected I get in console "1"
//Code n°2:
let num = 1;
function test(){
let num = 2;
console.log(num);
}
test() //As I expected I get in console "2"
But here is the problem:
//Code n°3:
let num = 1;
function test(){
console.log(num)
let num = 2;
console.log(num);
}
test() //I expected to get in console "1" and then "2" but instead I get an error.
When I run in my browser the code n° 3 Im getting this error:
Uncaught ReferenceError: can't access lexical declaration 'num' before initialization
If I look at code 1 and 2 I suppose that after running code 3 I will get in my console the number 1 and then number 2. But that isnt happening. Why?
Thank you so much!
The JavaScript exception "can't access lexical declaration `variable' before initialization" occurs when a lexical variable was accessed before it was initialized. This happens within any block statement, when let or const declarations are accessed before they are defined.
When the 'test function' is called, the function body gets executed. When it reaches to 'console.log(num)', it starts to search for the 'num variable declaration' (or 'num assignment' or 'num reassignment) in the test function scope. So it finds the variable declaration in the next line. The priority for searching for a variable is:
Current Scope
Closure
Scope Chain
So, when the variable declaration is found i the current scope, searching is not continued to scope chain. (It will not search for num variable in global scope.)
I guess this is the reason of the error, but as I am new to javaScript, I am not completely sure.
If you initialize the variable without redeclaring, it will work normally, now if you redeclar the variable, then this error will happen with let or var, because in the same scope, it is being called by the previous console.log().
It is not recommended that you re-declare let variables, if you need to, don't use the same in previous statement, note that if you comment on the first console.log(), the code will work again, this occurs exactly for the lifetime of the variable within this scope, in this case, let
let num = 1;
function test(){
console.log(num)
let num = 2;
console.log(num);
}
test()
Bacause in javascript functions and variables declared with var are hoisted, moved up to the top of the function/lexical block.
But let keyword respect the lexical flow. It pins variable where it is declared.
console.log try to access a variable that is declared bellow in the flow.
So move up manually your let declaration to be above de console.log or change it to var let num = 2; to let javascript engine move it above all automatically.
var num = 1;
function test(){
let num = 2;
console.log(num);
}
test()
or
var num = 1;
function test(){
console.log(num)
var num = 2;
console.log(num);
}
test()
or, to get access to global var num, which is shadowed by declarations from test's body, var or let, no matter
var num = 1;
function test(){
console.log(num)
//let num = 2;
console.log(num);
}
test()
Related
I written below script and executed in scratch pad.
baz();
var baz = function(){
console.log("Hello World");
}
When I try to execute above script, I got below kind of exception. I know, this expression comes because, hoisting is not valid for function expressions.
/*
Exception: TypeError: baz is not a function
#Scratchpad/1:1:1
*/
Now, I replaced the function name 'baz' with 'say_hello', and re run the application, it is working fine with no exception. Is there any reason for this behaviour?
say_hello();
var say_hello = function(){
console.log("Hello World");
}
say_hello();
function say_hello(){
console.log("Hello World");
}
This is the one which is really working fine with no exception
The reason is:
JavaScript only hoists declarations (variable and function declarations), not initializations
If a variable is declared and initialized after using it, the value will be undefined. For example:
console.log(num); // Returns undefined
var num;
num = 6;
If you declare the variable after it is used, but initialize it beforehand, it will return the value:
num = 6;
console.log(num); // returns 6
var num;
For more information:Only Declarations Are Hoisted
If I'm not wrong var lives is functional scope, because it's inside in function sandeep(). But if I'm doing console.log(lives) outside above the function then still I am getting console result as - New Delhi why? Can any one help me. (Is it because of Hoisting? it's moved on top...)
Screen shot without var define inside function
Screen shot with var inside function
Screen shot- write console.log after function call now it's giving undefined
I got my answer - It was my mistake, my chrome browser didn't refreshed properly. Thanks for every one for their answers.
console.log("Lives become global variable " + lives);
function sandeep() {
lives = "New Delhi";
return lives;
}
sandeep();
You are right about the fact that
var lives is functional scope
But you haven't declare the variable in the function. You need to use var lives = "New Delhi" so that its scope is only in the function in which it is declared.
If you directly assign lives = "New Delhi", it is assigned to global window object. Open browser console and try this.
a = 1
and then
window.a
You'll find that window.a is 1.
Let me know if it helps.
If I'm not wrong var lives is functional scope
This is right but you forgot the var in front of lives. If you define it as a variable you will get an error:
console.log("Lives become global variable " + lives);
function sandeep() {
var lives = "New Delhi";
return lives;
}
sandeep();
Only var are working as global & functional scope.
Global scope
var x=5;
function callvar(){
console.log(x);//5
var x=3;
console.log(x);//3
}
colsole.log(x);//3
function scope:
function one(){ var x = 5;
console.log(x)//5
}
console.log(x)// reference error
function two(){ var x = 4;
console.log(x)//4
}
console.log(x)// reference error
let & const are in block scope
functional scope is one type of block scope
if(true){
let x = 5;
console.log(x);//5
}
console.log(x) // reference error
I was explaining javascript closure to a friend like this:
function outer() {
var count = 0;
return (function(){
count++;
console.log(count);
})();
}
I was trying to show him that how does this 'count' variable is stored when the outer function is executed.
So I tried doing this in the javascript console and wanted to show him that when you do this in the console
outer(); // prints out 1
outer(); // calling again prints 2
outer(); // prints out 3
but actually this happened
outer(); // printed 1
outer(); // printed 1 again
outer(); // again 1
I don't understand whats going wrong here. Can someone guide me.
Thanks to #elclanrs. This is the working code.
function outer() {
var count = 0;
return (function(){
count++;
console.log(count);
});
}
Now when i call this function and store it in a variable
var myouter = outer();
myouter();
// 1
// undefined
myouter();
// 2
// undefined
myouter();
// 3
// undefined
It is because your count is declared inside the function, so it is "private" to the function scope, so every time your function is called, the variable count will be created and initialized to 0 then your inner function, aka, closure increments it, that is why it prints 1, then when your closure returns, your count variable is garbage-collected because its scope ends there -- within the matching curly braces, try moving count to the outermost outside any function, then you will get what you want, then your count will become a global variable which is not good in production code because you dont want to taint your global pool, and create memory leak problem. Closures are basically just inner functions like in Java.
You set count=0 every time you call outer(). If you want count to be private, meaning outside global scope, then I would use a module pattern like this:
var counter = (function(c){
var count = 0;
c.outer = function(){
count++;
console.log(count);
};
return c;
}({} || counter))
counter.outer();
or you can simply have outer() return a function:
function outer() {
var count = 0;
return function(){
count++;
console.log(count);
};
}
var myo = outer();
myo();
myo();
myo();
I have a little doubt in my mind, that how javascript interpreter works! Specially for the case I am mentioning here.
var a = 5;
function foo(){
debugger
a = 100;
if(false){
var a = 10;
}
a = 1000;
}
foo();
console.log(a);
Simply copy and paste the above code in browser's console, the expected answer is 1000.
What it returns is 5.
I have put debugger knowingly, when it hits debugger, the SCOPE section shows variable a as in scope with undefined. So the further assignment is done to local variable a, that was not meant to be created at all, as it is in false block.
I am aware about the scope of variable is not limited to {}, but it is limited to function. But this case is a surprise!
Can anyone explain this?
var declarations encompass the entire scope.
function() {
a = 5;
var a = 10;
}
is equivalent to:
function() {
var a;
a = 5;
a = 10;
}
So a is a local variable in the scope of the function, not global in the first part and local afterwards (that would be so complicated!).
Little formatting to your code.
var a = 5;
function foo(){
debugger
a = 100;
if(false){
var a = 10;
}
a = 1000;
}
foo();
console.log(a);
Hoisting is the keyword you are looking for. Javascript hoists the variables. Means it puts the declaration of your local variables at top of functions irrespective its going to be executed or not. So after interpretation your code looks like following.
var a = 5;
function foo(){
var a;
debugger
a = 100;
if(false){
a = 10;
}
a = 1000;
}
foo();
console.log(a);
So a becomes a local variable inside function, hence change of value inside function only changes local variable and not global. Hence console prints 5, global variable, value of which was never changed.
It's because you have a var a in the code. All declarations in the function are hoisted to the top, even if it looks like var a = 10; will never execute. Remove var and it will behave as expected.
Curious bit of code here...
var x = 5;
function fn() {
x = 10;
return;
function x() {}
}
fn();
alert(x);
Here's the jsFiddle
Is function x() {} called at all after return ?
Why not alert 10?
function x() {} is hoisted to the start of fn's scope, and this effectively makes x a local variable before x = 10; is evaluated.
The function is not set to 10.
Update: The sentence above is wrong. x is actually set to 10. var is not used to declare it, but even if it was, the last sentence in the quote below only refers to the declaration part of the name x, not its assignment to 10.
From MDN (emphasis mine):
function
Three forms with different scope behavior:
declared:
as a statement at the parent function top-level
behaves like a var binding that gets initialized to that function
initialization "hoists" to the very top of the parent function, above vars
var
function-scoped
hoist to the top of its function
redeclarations of the same name in the same scope are no-ops
function x float to the top, so you assigning the function to 10
You are declaring function x within fn; therefore, you are using the locally scoped version of x. It doesn't matter at what point the function x is declared. What you are actually doing when you set x to 10 is you are setting the function of x to 10.
This code also alerts 5:
var x = 5;
function fn() {
x = 10;
return;
var x;
}
fn();
alert(x);
The important point is that you are declaring a local variable x. Declaring a variable after the return statement also doesn't matter - it is still a local variable.
Remove the declaration and you get 10 instead because the x is no longer a local variable.
This is caused by the way variable hoisting works in JavaScript. Variable declarations are hoisted but not their assignemnts. Function declarations are also hoisted together with the function body (although function expressions are not).
So your code is effectively doing this:
var x = 5;
function fn() {
var x;
x = function () {}
x = 10;
return;
}
fn();
alert(x);
The x within the function is hence declared with only local scope and does not affect the x decalred in the main code.
This is because fn is an object, and x is a property of that object. Local-scope always takes precisence over globals.
X in fn() is a function
but x in the global scope is a var
remove the function x() {} part and x will be alerted 10