Access variable in if block - javascript

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.

Related

Can we access a variable declared using 'var' keyword inside a block? [duplicate]

This question already has answers here:
How JS hoisting works within functions?
(4 answers)
Closed 2 months ago.
A variable is declared using 'var' keyword inside a block ( {...} ). Can we access that variable outside the block?
I searched on several websites and the answer was 'yes'. 'Yes we can access the variable' it said.
But when I executed this on a browser console it said "the variable is not defined". Any thoughts why this is so?
Here's the screenshot of the same
I expected it to give 12345.
A variable is declared using 'var' keyword inside a block ( {...} ). Can we access that variable outside the block? I searched on several websites and the answer was 'yes'.
tldr; It's more precise to say Yes, unless that block is a function body.
var scopes a variable to the nearest function.
The body of the function (excepting some arrow functions) is a block.
Not all blocks are associated with functions.
{
var inBlock = 1;
}
console.log(inBlock); // This logs 1
function aFunction() {
var inFunction = 2;
}
aFunction();
console.log(inFunction); // This triggers a reference error
You can access the variable but that doesn't necessarily mean your variable will actually have a value before passing through said block.
var will be known throughout the entire function. So if you declare var x at the end of your function (or in an if-block nested in a while in another while) and assign it there, you will be able to call it at the start of the function, but the value will be "undefined" since it hasn't been assigned a value yet at that point of the execution.
Hence why var needs careful consideration on usage to make sure you actually need said variable outside the block where you're using/initializing it.
for-loops are (in my opinion) easiest to explain this with:
for( var i = 0; i < arr.length; i++ ) {
// do something
};
The variable i here will actually be known OUTSIDE the for-loop. It will be undefined before going through the for loop and will have the value of the last iteration after the for loop. (As oppposed to using let which will make it so variable i is not known outside the for-loop)
Variables declared with var has global and function scope but does not have block scope. Which means these variables are only accessible inside a function or globally.
// if we try to access it from function scope, it is not accessible
function greeting() {
var sayHi = "Hello"
return sayHi
}
console.log(sayHi) // sayHi is undefined. Because it has function scope
// if we try to access it from block scope, it is accessible.
if (1 < 2) {
var sayBye = "Bye"
}
console.log(sayBye) // prints 'Bye', because it has no block scope
After execution of the function, the variable will no longer be available and it will be referencing the globally scope which don't have your variable.

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.

Can variables declared in different local scopes be accessed?

I've been learning the javascript syntax for about a week now.
How can I move variables from one local scope to another local scope? So for example i've created a for loop off screen that adds an array of values to one main array every round of the loop, the main array is called x. I've not included the loop as it's irrelevant to the issue. In the example below, the purpose for variable y off screen is essentially to take the values contained within the arrays of x to retrieve more data via a web scrape.
Context aside, I can't access the y variable declared inside the if statement. As you can see below i'm trying to use it as an argument in a function called functionName.
if (x.length === 1){
let y = x[0]
} else {
let y = x[0][2]
};
functionName(y)
Is it better practices to duplicate the function call for every outcome of the if statement like this
if (x.length === 1){
let y = x[0]
functionName(y)
} else {
let y = x[0][2]
functionName(y)
};
Or can different local scopes actually communicate with each other.
It definitely feels less practical to call every function for every outcome of the if statement, especially if it's a larger conditional switch statement.
Thanks in advance.
How can I move variables from one local scope to another local scope?
You can't. That's the point of scopes.
Is it better practices to duplicate the function call for every outcome of the if statement like this
No. Put the variable in a shared scope.
{
let y;
if (x.length === 1){
y = x[0]
} else {
y = x[0][2]
};
functionName(y)
}
You can't "move" the scope of a variable dynamically. A variable's scope is completely determined by the block (or function) it's declared in. For two blocks to be able to reference the same variable, that variable must be declared outside of both blocks, in an ancestor block:
let y;
if (x.length === 1){
y = x[0]
} else {
y = x[0][2]
};
functionName(y)
But, in this case, since you want to conditionally assign to y, you should use the conditional operator:
const y = x.length === 1
? x[0]
: x[0][2];
functionName(y)
In Javascript, now, there are two types of scope: Block Scope and Function Scope. First there was light, ehm sorry that was another stackexchange site, first there was only function scope.
With the introduction of this new scope also introduced was the different way of declaring a variable, let, also const, both of which defines a block scoped variable. Before there was only var which defined and still defines a function scoped variable.
Block Scope is inside the if, for and similar blocks which usually enclosed lexically by a pair of curly braces {}, not to be confused by the objects, which have same enclosing as well.
Function scope is inside the functions, of all type whether fat arrow or normal ones, hence the name.
So you should either define the y with let, const or var once and outside of the if blocks you did. Once you the definition outside of the block you can use any of them since block scope is no longer your problem, or alternatively, define it in the first if block if you must with var so it is still in the scope outside of the if block it is defiend in then do use it in your assignment in else as y = something since it in the scope in there too. Though first way is better.
let y;
if (x.length === 1){
y = x[0]
functionName(y) // or put call outside the block
} else {
y = x[0][2]
functionName(y) // or put call outside the block
};
// functionName(y); // or put call outside the block here
Also note in your first example the let y in the else block would create a different variable than the one defined in the preceding if since let, also const, defines a new block scoped variable.
Finally, variables cannot be moved from one scope to another or be accessed from outside of the scope they defined in per se, but you can use the scopes to your advantage like defining a variable you need in some of the scopes you have access to, or opposite if you need to enclose it to a scope. It may also be possible to create some custom constructs to share scopes between blocks or functions, I can imagine closures, however this may be a bit out of scope of the post now.

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.

scope and availability of a variable inside a function

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.

Categories

Resources