Block scoping with nested var shows different errors - javascript

I'm trying to understand block scoping on ES6 and found the following issue (maybe I'm just misunderstanding the concept):
In the first test I tried the following and got the commented error:
{
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
var x = true; //Identifier 'x' has already been declared
}
}
}
console.log(x)
But when I try to get the type of the "already declared" x I get :
{
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
console.log(typeof x); //this throws Uncaught ReferenceError: x is not defined
}
}
}
console.log(x);
I'll keep trying to see what is going on, any ideas are accepted.

Actually, your error comes from the final console.log(x);. Removing that line makes your code work fine.
This error makes perfect sense. x is only defined in inner blocks; it doesn't exist in the outer scope.

First of all, you need to know the difference between let and var
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope. An explanation of why the name "let" was chosen can be found here.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Second, you got this error "Identifier 'x' has already been declared" because you already have "let x" so you can't use "var x". However, if you change the var to let, it will work.
Example to understand scoping:
function test() { // first scope
let x = 1;
let y = 2;
console.log(x, y); //1 2
function test2() { // second scope
let x = 2;
let z = 3;
console.log(x,y,z); //2 2 3
}
test2();
console.log(z); //z is not defined... notice z is defined in the second scope, not the first one
}
test();
Keep in mind, you can access variables from higher/global scopes in inner scopes, but you can't access variables from inner scopes in higher/global scopes.
Read this: What is the scope of variables in JavaScript?
EDIT:
If you do this, it should work fine
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
x = true;
}
}
console.log(x)
OR
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
let x = true;
}
}
console.log(x)

Related

JavaScript: implement let-working with var

So I have a code that clone let-behavior. But I don't undestand how and why it is working. Can someone explain it?
(function() {
var a = 2;
})()
let is scoped to the block it appears in.
var is scoped to the function it appears in.
By replacing a block with a function (which is immediately invoked) var is scoped to the same lines of code as let would be.
Where you can only use var variables but you want to ensure that a variable declaration is not going to overwrite another pre-existing variable of the same name, you can use an IIFE to scope that variable to the function. This in effect creates a "block", similar to the second example below.
var variables are scoped to functions:
var a = 1;
let b = 1;
(function() {
var a = 2;
let b = 1;
})();
console.log(a); //=> 1 (a is not overwritten because the second `var a` is function-scoped)
console.log(b); //=> 1
let variables are scoped to blocks:
let a = 1;
var b = 1;
{
let a = 2;
var b = 2;
}
console.log(a); //=> 1 (a is not overwritten as let is block-scoped)
console.log(b); //=> 2 (b is overwritten as var is not block-scoped)
It's worth mentioning that you can redeclare a var variable, hence why it would be possible to overwrite an existing var variable of the same name. However, you cannot redeclare a let variable:
var a = 1
// will not error as `var` does not prevent redeclaration
var a = 2
let b = 1
{
// will not error as `b` is not declared in this block
let b = 2
}
// will error as `b` is already declared in this scope
let b = 3
You can read more about let and var in this question and its answers.

Why it is printing i value (it is already outside the scope)?

In JavaScript why i value is printed when we are printing outside the scope
test();
function test(){
for(var i=0;i<10 ;i++){
console.log(i)
}
console.log('outside'+i)
}
As comparison to Java it is giving compile error?
for(int x = 10; x < 20; x = x+1) {
System.out.println("value of x : " + x );
}
System.out.print("value o " + x );
JavaScript has function scope not block scope (C, C#, C++, Java and many other programming languages have block scope). In JavaScript a variable defined anywhere inside the function will be visible anywhere in the function:
function test() {
console.log(x); // logs undefined, because x is a variable that has no value yet
if (true) {
x = 42;
} else {
var x = 5; // x is not set to 5, but it is acknowledged as a variable
}
console.log(x); // logs 42 because the value in variable x has been set to 42
console.log(y); // Error because y is not declared
}
One thing you might see mentioned regarding this is var hoisting. This means the JS interpreter will act as if all the var statements in a scope (function or global) are moved at the begining of that scope:
function foo() {
console.log(x,y);
var x = 4;
var y = 2;
var x = 0;
}
// is equivalent to:
function foo() {
var x,y;
console.log(x,y);
x = 4;
y = 2;
x = 0;
}
More details on MDN
Also, note the difference between var and let from ECMAScript6
The scope of i in this case isn't the for loop, but the test() function.

JavaScript code executing after return

In the following example, JavaScript seems to be completely ignoring my return statement, and just carrying on executing code.
var x = 1;
(function() {
x = 2;
return;
var x = 3;
})();
console.log(x); // Outputs 1 in both Chrome and FF
Surely the code should output 2? If I remove the var keyword from var x = 3, it outputs 2 as expected. Is there some strange compiler optimization at work here?
No, the code shouldn't output 2 because variable declarations are hoisted so your code is equivalent to
var x = 1;
(function() {
var x;
x = 2; // changes the internal x variable
return;
x = 3; // does nothing because it's not reached
})();
console.log(x); // Outputs the outside x, which is still 1
The line
x = 2;
only changes the internal x variable which shadows the outside one.
The scope of a non global variable is the entire function in which it is declared. From the start of this function to its end.

Why is my global variable shadowed before the local declaration?

x = 1;
alert(x);
var y = function() {
alert(x);
var x = 2;
alert(x);
}
y();
The result of the 3 alerts is: 1, undefined, 2 (Chrome 25)
My question is: why the second alert is undefined? Why not 1? Isn't there a global variable x?
Due to hoisting, this is what gets executed:
x = 1;
alert(x);
var y = function() {
var x; // <-- this gets hoisted up from where it was.
alert(x);
x = 2;
alert(x);
}
y();
At the start of function y(), the local variable x is declared but not initialized.
The variable declaration in the function is hoisted to the top. So it technically looks like this:
var y = function() {
var x;
alert(x);
x = 2;
};
The local variable overshadows the global one. That is why the alert returns undefined.
Since scope in JavaScript is a function object. When you execute some code in a function(your code sample), "alert(x)" will find if there's any definition of "x" in the function. So, there's a "var x = 2" in this function. But the JavaScript runtime will explain your code like this:
x = 1;
alert(x);
var y = function() {
var x;
alert(x);
x = 2;
alert(x);
}
y();
So, the x in the second alert is "undefined" not "1". So when you declare some variable in a function, I recommend you to declare the variables in the top of your function.

Declaration inside eval in javascript

Consider the following two JavaScript snippets:
var x = 2;
function f() {
var y = x;
eval('var x;');
return y;
}
vs.
var x = 2;
function f() {
var y = x;
var x;
return y;
}
The only difference is I've replaced eval('var x;'); with var x;.
The first one returns 2, but the second one returns undefined. Why?
Variable declarations are hoisted by the parser to the top of the lexical scope. In the second block of code, the way it's actually run is:
function f() {
var x, y;
y = x;
return y;
}
Function declarations are also hoisted. The net effect is that a variable declaration should be considered to always include the entire lexical scope in which it appears. If variable x is declared with var anywhere in a function, then every reference to x in that function is to the local variable.
In your first example, the eval() line is just a regular expression statement, so it's executed in order of its appearance in the function.
Because with the second one, the var is hoisted* to the beginning of the function, before any other statements are executed.
So its as though you code was this:
var x = 2;
function f() {
var x, y
y = x;
return y;
}
But with the first one, the var x is part of the eval() expression, so it doesn't have the opportunity to be hoisted* as in the second one.
*The term "hoisted" is not an official term. Its just a word that people use to describe the fact that declarations happen before any expressions are evaluated within the execution context. Function declarations are also hoisted.
That's because when the interpreter is in scope of function it sets value undefined to all variables which are declared inside it (with var keyword prefixed). It's no matter where you've put the declaration, if there's a variable declaration inside a function the variable's value will be undefined until you set it's value explicitly. In the first case you have eval('var x;') which is still not evaluated when the value of y is being set. That's why the value of y is 2, because the value of the variable x in the upper scope is 2.
The same will be here:
var x = 2;
function foo() {
var y = x;
console.log(y); //undefined
console.log(x); //undefined
var x = 3;
}
function bar() {
var y = x;
console.log(y); //2
}
var x = 2;
function foobar() {
console.log(x); //undefined
var x;
console.log(x); // undefined
x = 3;
var y = x;
console.log(y); //3
}
The eval is evaluated just as a regular expression.

Categories