scope and availability of a variable inside a function - javascript

I am learning javascript and my question might not be used practically anywhere but for interview purpose I want to understand this clearly. below is the code. the first alert alerts 'undefined' and the second one is '4'. the second one is understandable. I want to know why the first alert doesn't alert '5' and undefined? whats the concept behind the same?
Thanks.
var x = 5;
function check(){
alert(x);
var x = 4;
alert(x);
}
check();

var is always hoisted (moved) to the begining of the scope. Your code is equivalent to this:
var x = 5;
function check(){
var x;
alert(x);
x = 4;
alert(x);
}
check();
As you can clearly see, the local x hides the global x, even if the local one doesn't have a value yet (so the first alert shows undefined).
A little extra: conditionals or other blocks don't influence hoisting the var declaration.
var x = 1;
(function() {
x = 3;
if (false) {
var x = 2; // var will be moved to the begining of the function
}
})()
console.log(x) // 1

JavaScript has some concepts that take a little getting used to for sure and sometime the answer for what seems to be a simple question is long winded but i will try to be as quick and concise as possible.
In JavaScript, variables are scoped by functions and you have two places that a variable can be scoped(have context) either 'globally' or 'locally'. The global context in a web browser is the 'window' so in your code example var x = 5; is a global variable. The local context in your code is within your check function so var x = 4; is a local variable to the check function. If you had more functions those would have their own function scope(context) and so on. As a word of caution if you forget the word "var" when declaring a variable inside a function it will become a 'global' variable, be careful. Now that we have the 'global', 'local' scope down what happens before a Javascript programs runs?
A few things happen in the Javascript Engine before your code is executed but we will only look at what happens to variables. Variables are said to be 'hoisted' to the top of their functional context or scope. What that means is that the variable declaration is 'hoisted or moved to the top and assigned the value 'undefined' but not initialized the initialization remains in the same spot they were. This hoisting also makes the variable available anywhere within the function it was defined.
So it looks something like this:
//to be accurate this is hoisted to its functional scope as well
var x;
x = 5;
function check() {
//declaration of 'x' hoisted to the top of functional scope,
//and assigned undefined
var x;
//this will alert undefined
alert(x);
//initialization of variable remains here
x = 4;
//so after the initialization of 'x' this will alert 4
alert(x);
}
check();
Happy Coding!!!
As an aside: They have a new feature named 'let' that you can implement to add block-level scoping in I believe EMCAScript 6 but is not implemented in all the browsers as of yet so that is why i placed it in an aside.

Related

In the block scope even after initialisation with undefined var type of variable logs out unexpected value

function show() {
var x = 10;
if (true) {
var x = 20;
}
console.log(x); // 20
}
show();
But when I not initialise the 'x' manually which is inside the 'if-statement', it initialise with undefined and hoisted to the top and should log the most recent value which is undefined , as 20 is logs out in the above example. But it logs out 10.Why?
function show() {
var x = 10;
if (true) {
var x;
}
console.log(x); // 10
}
show();
From MDN - var:
Duplicate variable declarations using var will not trigger an error,
even in strict mode, and the variable will not lose its value, unless
another assignment is performed.
So, unless you re-assign any value to x, variable declared with var will keep its value.
Re-declaring x inside the if block does not create a new variable; x is created only once.
From the Ecmascript spec - 14.3.2 Variable Statement:
A var statement declares variables that are scoped to the running
execution context's VariableEnvironment. Var variables are created
when their containing Environment Record is instantiated and are
initialized to undefined when created. Within the scope of any
VariableEnvironment a common BindingIdentifier may appear in more than
one VariableDeclaration but those declarations collectively define
only one variable.
That is why x in the following statement
var x;
doesn't implicitly gets initialized with undefined; this re-declaration statement didn't re-create the variable x.
function show() {
var x = 10;
if (true) {
var x = undefined; // re-assigned
}
console.log(x);
}
show();
Note on hoisting: Unless you know this already, variables are NOT literally hoisted/moved to the top of the scope in which they are declared; variable declarations are processed before the code execution, this is why they appear to have moved to the top of the scope.
For more details, see: MDN - var hoisting
So if you are trying to relate above both example, you might confused. see both examples in different way, you will get the answer.

Why does Chrome debugger get undefined when accessing variables in Closure? [duplicate]

This question already has answers here:
Why does Chrome debugger think closed local variable is undefined?
(7 answers)
Closed 4 years ago.
Code:
function test4() {
var x = 10;
var y = 100;
// inner referred x only
function inner () {
console.log(x);
debugger;
}
// inner2 referred y to make sure y is in the scope of inner
function inner2 () {
console.log(y);
}
return inner;
}
var foo = test4();
foo();
y is in the scope of inner even only inner2 which never been used refer to it. I checked the result in scope and x, y are there:
But when I checked variables in watch panel and console, I can't get all of them:
It's weird that y is in the scope but get not defined when using debugger.
So, is it means that debugger can not access variable that not used in current context even it's in the closure or it just a bug? (My chrome version is 51.0.2704.103 m)
It's similar to Why does Chrome debugger think closed local variable is undefined? but not the same. Because inner2 in my code make sure that y is in the closure. And actually my question is opposite to Louis's answer under that question.
You are a first-hand observer of the internal mechanics of scope-optimization. Scope optimization is checking to see which variables are used in the current scope and optimizing out access to unused variables. The reason for this is because in the machine code generated from JIT compilation of javascript, the whole concept of variable naming is lost. But, to maintain javascript compliance, the JIT compiler associates an array of used local variables to each javascript function. Observe the following code.
(function(){
"use strict";
var myVariable = NaN; // |Ref1|
var scopedOne = (function(){
var myVariable = 101; // |Ref2|
return x => x * myVariable;
})();
var scopedTwo = (function(){
var myVariable = -7; // |Ref3|
return x => x / myVariable;
})();
console.log("scopedOne(2): ", scopedOne(2));
console.log("scopedTwo(56): ", scopedTwo(56))
})();
As seen above, Javascript is a scoped stack-based language. If Javascript was not a scoped language, then the variables used in the functions would depend on the values of the variables at the location where the function was being executed. For instance, without a scope, scopedOne would use the value of myVariable at |Ref1| (NaN) instead of at |Ref2| (101) and would log NaN to the console. Back to the main point, in the machine code, when the debugger comes in, it can only figure out where the actual locations in memory are of the used variables since only those memory locations have persisted to machine code as only those variable have been used. The memory locations of the rest of the variables remain a mystery to it. As you have observed, this has the secondary side-effect of making unused variables in the scope "invisible" to that function. However, there is a solution.
To circumvent this problem, simply wrap the debugger; statement in an eval to force the browser to do an expensive variable lookup of all the variables in the scope. Basically, the browser has to go back to the original source code, examine it for the original names of the variables in the scope, and figure out where the values of the variables are stored by the JIT-generated machine code. Open up developer tools and run the snippet below. Then go to the prior level in the "Call Stack" panel and observe how the visibility of the value of the variable y changes from visible inside eval to invisible outside eval.
function test4() {
var x = 10;
var y = 100;
// inner referred x only
function inner () {
console.log(x);
eval("debugger;");
}
// inner2 referred y to make sure y is in the scope of inner
function inner2 () {
console.log(y);
}
return inner;
}
var foo = test4();
foo();

Access variable in if block

var func = function () {
var i: number = 0;
if (i == 0) {
var y: number = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
func(); // output: 1
As you can see, I've declared variable y inside if block. So, I think it couldn't be referenced outside the scope.
But, when I've tried to run the code, the output is 1.
Is it an issue in typescript/javascript?
Variables in Javascript are hoisted, meaning that var y is moved to the top of the function as if it were declared there.
Initialization, however is not hoisted, so if you change i to be something other than 0, the variable y will still exist, but it will have the value undefined.
This means that the function is exactly equivalent to:
var func = function () {
var i: number = 0;
var y: number;
if (i == 0) {
y = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
To get the behavior you expect, you need to use let, which is a part of ECMAScript 2015 (ES6). It is block scoped, as you expect. It will also effectively work so that it is accessible only from the point of definition onwards, which is also probably as you would expect.
If you re-declare a JavaScript variable, it will not lose its value.
The second reference might pave way for a new variable syntax. Actually if you recall variable declaration is not neccessary in javascript. Simpe
y=1;
also works.
The second time when you reference y, outside if block, in my opinion, it tries a re-declaration and retains the old value.
Reference - http://www.w3schools.com/js/js_variables.asp
& http://www.w3schools.com/js/js_scope.asp
Javascript has function scope afaik. Any variable declared within a function, should be accessible from anywhere within the function. So, if you have a function checking if i==0, then you can achieve what you are trying to achieve.
This is as it is supposed to be. Javascript scopes by function, not by block. (This does make it unlike many popular languages)
Variables declared like var myVar = 10; will seep into nested functions but not the other way around. Variables declared like myVar = 10; will go global.
I couldn't find anything which suggested that typescript was any different.
Variables declared inside of an if statement are not scoped to the if statement. They're scoped to the current execution context. There's the Global execution context and then when a function is run, it creates it's own execution context. Inside of your function, you created the variables y and i. It doesn't matter that y was created inside of the if statement, because once it runs, y is created in the scope of the function. So then you do y.toString(), which can access y because it's scoped to the function not the if statement. That's why you get the output of 1. This is not an error, it's by design.

Is the Javascript variable declaration shorthand making variables global or local?

I understand that the variables in the following function will only be available in this function;
function(){
var x;
var y;
var z = 3;
});
But I don't know about the following in shorthand. What is their scope? (Y and Z)
function(){
var x, y, z=3;
});
And If there's something I can go read somewhere about this shorthand please provide a link.
Thanks.
Both represent exactly the same thing, and thus the variables carry same scope. They will be defined everywhere inside this function.
You can read more about it here.
The variables declared without var keyword are made global variable.
Don't know the reason behind this. But I have tested this.
Also, in your 2nd example as well, the variables will be local to that function only as you have used var for 1st variable and it is continued by using comma.
Try this example
var a=10:
Function test()
{c=11; var b=12; a=0;}
console.log(a);
test();
console.log(a);
console.log(b);
console.log(c);
In javascripts,
If you assign a value to a variable that has not been declared, it will automatically become a GLOBAL variable.
In your case you are declaring then assigning value (var x,y,z = 3).
They all will be in local scope only.
For learning more about scope you can go through W3School.

if a function's lexical environment is created at the time the function is *defined*, then why can a free variable be declared *after* the function?

EDIT: thanks for the answers, I think I get it now. It requires an understanding of scope and hoisting. Below is a new example that I think illustrates both well:
var a = function (){
alert(x);
}
var x = 1;
(function(){
var x = 2;
a();
})();
The above alerts 1. Lexical scope is illustrated by the fact that this alerts 1 and not 2, and hoisting is illustrated by the fact that the "var x = 1" line comes after the declaration of a and definition of the anonymous function with the "alert(x)". Allegedly, hoisting means that the above is equivalent to the below (source: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html):
var x;
var a = function (){
alert(x);
}
x = 1;
(function(){
var x = 2;
a();
})();
So since x is effectively initialized before the function definition, the x in "alert(x)" is the same x that subsequently gets set to 1.
Since JS uses lexical scope, the line "var x = 2" does not override the x associated with a.
Is that about right?
---original question---
I've spent pretty much all day trying to figure this out. I've read a few articles on scope and closures in Javascript, but this still eludes me.
I'm told that a function's lexical environment is created when the function is defined, not when it is executed.
So if there is no variable called x declared anywhere in my program, then what is the closure environment for the anonymous function that a points to when I do this?:
var a = func(){
var y = 7; //just for illustrative purposes
alert(x);
});
My understanding is that an environment is a mapping of variable names to values...so it would be
y: 7
x: ?
Is that correct? The following code alerts "10":
(function (){
var a = function(){
alert(x);
};
var x = 10;
a();
})();
My guess would be that when a is called, the JS checks the closure environment for a mapping for x and finds none, and subsequently checks the local environment and finds the x set to 10 by "var x = 10". Is that right?
If that were the case, then I would expect the following would also work, and yet it does not:
var a = function(){
alert(x);
};
(function (){
var x = 10;
a();
})();
What I would expect to happen is that, when a is executed, and "alert(x);" is run, it checks the closure environment for x, finds none, then checks the outer environment where "var x = 10" is and finds that x. But instead I get an error that x isn't defined.
Maybe it would help if I could know what 'preparatory' work is done by the interpreter when the anonymous function that a is set to is initially defined--i.e. when the interpreter encounters the x in "alert(x)".
Thanks
the JS checks the closure environment for a mapping for x and finds none
In fact it does find one. The position of the var statement does not matter, the name x is still bound to the closure of the outer function. You can think of the declarations being collected during the parsing step and moved to the front (this process is called hoisting).
Thr process of walking up the scopes surrounding an expression in the source code is called lexical binding.
For your second example to work you'd need dynamic binding, which JS does not support (except for globals).
Think of closure as a stack. Each function has a map/hash in that stack. Here's an example where each level has a value of x that is overwritten by a sub-closure.
function a(){
var x = 2;
function b(){
var x = 3;
function c(){
var x = 4;
}
}
}
When referencing a value of x, the js processor looks in the current closure. Finding undefined, it walks up the closure stack attempting to find a value. Only when reaching the top level or 'global' scope does it give up and give the value of 'undefined'.
Your example here:
var a = function(){
alert(x); //no value of x in this closure
};
//no value of x in this closure either
(function (){
var x = 10; //this is a completely separate stack
a(); //no value of 'a' in this closure, but there is one in global scope
})();
I can see the confusion on the 'a' function not knowing about the 'x' in the anonymous function. Closure scopes are defined 'as written' not 'as called'. You can't inject or mess with variables in a functions closure scope from outside that closure scope. It is one of the things about js that drives me crazy and that I wish were different. I'd so love to have a set of keywords for messing with closure scope...

Categories

Resources