Why global let declarations get overridden by unscoped variables? - javascript

When we create a variable without specifying let or var it gets added to window object in browser. For example
function change(){
val = 20;
}
change();
console.log(window.val); //20
console.log(val); //20
Here I am getting both console logs print value 20. But I do the same using let it doesn't get added to window object. I saw this answer with the explanation why this is happening.
let val = 20;
console.log(window.val); //undefined
console.log(val); //20
Now, in the below code, can someone explain, when I assign an un scoped variable inside the function why it is not getting added to window scope? Instead how it is changing the value of the variable declared with let
let value = 10;
function change(){
value = 20;
}
change();
console.log(window.value); //undefined
console.log(value); //20 why this is 20?

MDN says this about var:
The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global. If you re-declare a JavaScript variable, it will not lose its value.
MDN says this about let:
Variables declared by let have their scope in the block for which they are defined, as well as in any contained sub-blocks. In this way, let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function:
They both end up in a scope which is then propagated to child scopes but which scope they end up in and how they go about determining that scope is different.
Note that the entirety of a <script> element does have an implicit block and this implicit block inherits window as an ancestor scope. Variable declared by var end up scoped into window while variables declared by let are scoped into this implicit block.

Declaring variables with let in the top-level of your script lets you access it inside your entire script and even outside. Inside your function, you are not assigning a value to an unscoped variable.
Even if you were to write your function as below, it would not assign to the window object as it would then be function scoped.
function change(){
var value = 20;
}

Related

Scope chain and global object in javascript

When we declare a variable with the var keyword in the global scope var x = 10;, a property with the same name is created in the global object (window, global, self, globalThis, depending on the environment). So, here is my question:
If I try to access that variable console.log(x) js will look for it into my declared code first to see if its there or it will jump directly to the global object? I know that if I do this:
let myVar = 20;
globalThis.myVar = 30;
console.log(myVar) // 20, so my let declaration is readed first.
But what happens with var declarations?
In browser children of window object are directly accessible by their names without explicit window. when you create a local variable however you shadow the name even if exists under window so yes local will be accessed first
In programming this is called variable shadowing you can read more on the wiki I linked
PS. If you are on global scope and use var it will be as if you declared the thing under window itself I will demonstrate this with a snippet
var foo = 12;
console.log(window.foo)//12
window.foo=10
console.log(foo)//10
//However if you use let or const this will not happen

How variable can be accessible outside the for loop

In the code below, I have declared variable i on for loop , and trying to access variable i and I can get the last updated value of i, how.
for(var i = 0; i <= 10; i++){
console.log(i);
}
console.log(i,'outside');
The var statement declares a variable in the scope of the current function, not the current block (which is what the let statement is for).
After the for loop, you are still in the same function, so the variable still exists (with whatever value it was last set to).
(NB: For the purposes of var, the code which runs outside of any function is effectively treated as being in a function of its own).
Well, you are using var, and that's exactly a var type should do!
We have var and let, let's see how they work.
when you declare your variable like this :
let something;
You only access something in that very scope (for example your own for loop), and outside the scope, you cannot have it. On the other hand, when you are using var type, like this :
var something;
You are able to use this variable outside the scope ( again like your own for loop )
Notice that we are not talking about global variables. we are just talking about scopes.
If you rather declare a global variable, just use var in the global scope.

How should I access to overwritten variable in overwritten function?

I'm not able to understand of how should I get to particular variable a in next code:
var a = 1;
console.log(a);
function local() {
var a = 2;
console.log(a);
function local() {
var a = 3;
console.log(a);
function local() {
var a = 4;
console.log(a)
}
local();
}
local();
}
local();
I know this is artificial example but I can't go to sleep without the answer :)
So how should I get a particular variable a from any of overwritten function?
Thanks.
When you declare a variable in the local scope with the same name as a variable in a higher scope, the new declaration hides the higher scoped variable and there is NO way to access that higher scoped variable from the local scope.
This is just how Javascript is designed. There isn't some magic way around it. If you want access to the higher scoped variable, then don't declare a local variable with the same name. Pick a different name.
If the top-most variable is in the global scope, then you might be able to access that variable with a global prefix such as window.a or global.a (depending upon which environment you're running in). But, the intermediate variables that are not in the global scope are not accessible.
you can access global variables by the window object like this
var aa=11;
function my_func(){
var aa=22;
alert("local: "+aa+" global: "+window.aa);
}
but there is no way of accessing the local variables outside the function, as they do not really exist out there!

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.

Shouldn't this variable default to "top-level"?

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.

Categories

Resources