JavaScript code executing after return - javascript

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.

Related

Block scoping with nested var shows different errors

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)

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.

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.

Javascript code semantics

if(myVar = img.parent('a').length > 0){
var Y = 1;
}else{
var Y = 2;
}
When I run this code myVar (being announced for the first time) takes the value of img.parent('a').length > 0 and becomes either false or true depending on the case.
First Question:
Is this a correct way of defining myVar?
Second Question:
Am I defining Y for the second time? Is my second 'var' excess?
i.e. should i just write Y = 2;
First question: IMO, using an assignment on the condition of the if statement, might cause confusion, also if myVar is not declared previously with the var statement it might become a global variable.
Second question: No, you aren't re-declaring Y a second time, actually Y is defined before any assignment, it is hoisted to the top of its enclosing scope.
This is how actually var behaves in your code:
var Y; // declared and initialized with `undefined`
if (myVar = img.parent('a').length > 0) {
Y = 1; // assignment
} else {
Y = 2; // assignment
}
You can observe this behavior with the following example:
var Y = 'foo';
(function () {
alert(Y); //alerts `undefined`
var Y;
})();
As you see, the alert is before the var declaration in that function, but since the var statement is hoisted, the Y variable from this new scope is set up before the execution, when the Variable Instantiation process takes place.
The most straight forward approach, would be to declare and assign myVar:
var Y, myVar = img.parent('a').length > 0;
if (myVar) {
Y = 1;
} else {
Y = 2;
}
// Or Y = myVar ? 1 : 2;
Or even shorter, in a single var statement:
var myVar = img.parent('a').length > 0,
Y = myVar ? 1 : 2;
//...

Categories