JavaScript Lexical Scoping and Life of Variable - javascript

I was curious why this works:
function doThis(){
counter = 0;
return counter;
};
console.log(counter); // returns "reference error: can't find variable"
which makes sense, as the variable does not exist outside of the function. But if I make a function that self executes:
(function doThis(){
counter = 0;
return counter;
})();
console.log(counter); // returns 0
How come the variable counter still exists? It's not a closure, there's nothing that seems to be referencing this variable from the outside, so shouldn't it be destroyed by garbage collection?

You are creating it as a global as you haven't included var before the variable name.
The function in the first example hasn't been invoked so the variable has not been created yet, in the second one it has so that is why you get 0
What your code should be doing is:
function doThis(){
var counter = 0;
return counter;
};

First edit them so that it is instantly clear what's happening (no leaving out var hacks):
function doThis(){
window.counter = 0;
return counter;
};
console.log(window.counter); // returns undefind
And:
(function doThis(){
window.counter = 0;
return counter;
})();
console.log(window.counter); // returns 0
Can you now see what's happening? The function defines a global variable so of course it's not available until the function is called. window refers to the [object global] in browsers.
This is the reason you always want to use either global.something OR var something, so that it's very clear to anyone whether you intend to use global or local variable. If you used var in the OP, the variable would be local.

Since you are not declaring it with "var" it gets assigned to the global scope which is visible out side of the function. In the first example you are not executing the function so the counter is never defined where as in the second example you invoke the function and counter gets assigned to the global scope

In the first example you haven't called the function and so counter doesn't exist yet (because the code inside the function hasn't executed yet). In the second example, you have defined a function literal and you are self-invoking it. The code inside the function execute and counter is now defined.
Furthermore counter is a global variable because you haven't defined it using var and so it is visible to the scope outside the function. It's the same as doing window.counter = 0.
Now if you had done the following:
(function doThis(){
var counter = 0; //notice the var
return counter;
})();
counter would still be undefined because it is local to the scope of the function.
So to recap:
In the first example counter is undefined because the code hasn't run yet. If you actually call the function, you will get the same behavior as the second example.
In the second example counter is defined and is a global variable (basically the same as window.counter) and it is defined because the code inside the function was executed when you defined it and self-invoked it.
In the third example counter is unknown to the global scope because it is local to the function inside which it was defined (because var was used).

As you know, in JavaScript, if you declare a variable without "var" keyword, it will be added to the global scope(window object).
But if a variable is declared within a function without using "var" keyword, it won't be added to the global scope(window object) until that particular function is invoked.
In JavaScript, you have to understand about execution context creation.
when the complete JS file is interpreted, the the memory is allocated for all the functions and variables(hoisting).
Please note that all the variables which are declared outside of the functions are added to the global scope(window object).
Execution phase:
As JS code execution is synchronous(only one line at a time) and single threaded, an execution stack is created and the "global execution context" is pushed to the execution stack.
If a function invocation is encountered in the execution, "function execution context" is created for the corresponding function and pushed to the same stack.
Now during function execution, JS engine parse the code and if it come across a variable, the memory is allocated and if the variable is declared without "var" keyword, it will add this particular variable to the global scope. otherwise that particular variable will be part of function scope(local scope).
Now let's check your code snippets:
function doThis(){
counter = 0;
return counter;
};
console.log(counter); // returns "reference error: can't find variable"
in this example, as the doThis() function is never executed, variable "counter " is not allocated any memory and not part of any scope(global/local). hence in the console log, you see a reference error.
(function doThis(){
counter = 0;
return counter;
})();
console.log(counter); // returns 0
As its a self invoking function, "counter" variable will be allocated memory and moved to the global scope(window object). hence you can see the value of the "counter" variable in the console log.

Related

Closure of function defined as an argument

Disclaimer: This question is purely curiosity driven and has to do a lot with how the javascript works.
I understand why the following code works. Due to closures, foo has access to the scope where a resides. This makes sense.
var a = 10
var foo = function(){
console.log(a);
}
setTimeout(foo,1000)
However, i wonder why the following also works (explained right after).
var a = 10
setTimeout(function(){
console.log(a);
},1000)
The function is defined in the argument of the function receiving it and essentially was never a closure to the scope that contains a. We know that when a function receives an argument, it creates a local variable for that argument so for example
var outerVar="5"
var bar = function(a){
//implicitly, var a = outerVar happens here
console.log(a)
}
bar(something);
So following that logic, the function passed to setTimeout couldnt have access to a and yet it does.
Im suspecting that when a function is defined in the argument space what happens is, it realy is defined before being assigned as an argument but have no proof of that. Any pointers highly appreciated.
Thanks a bunch.
It's not exactly closure, but it's close.
Strictly speaking, closure is when a variable's scope ends, but is still enclosed in an inner function that still lives on:
function createTimer() {
let counter = 0;
return function() {
return counter++;
}
}
const timer = createTimer(); // function() { ... }
console.log(timer(), timer(), timer()); // 0, 1, 2
The function in which counter is defined has returned, the scope ended, and under normal circumstances, counter should have died and garbage collected. But the inner function returned from createTimer() still has a reference to it, from the enclosed scope, that is a closure.
In JavaScript, every function has access to all of the scopes of all of its ancestors, this is what you're seeing here.
The function passed to setTimeout() has access to a because a is defined in the scope around it.
When you look at a javascript code and see how it works, the best way according to me is first understand the javascript engine how it works.
First it traverses the code and assigns all the variables to the scope and further more in the second trace it assigns the values based on the scopes.
So in your first code,
The engine first traverses and assigns
var a to global scope,
var foo as global scope,
Then when setTimeout runs it calls foo function and logs the value of a as that of the global a as it doesnt have any local “a” so checks the lexical scoping.
In your second code,
Var a is again global scoped
and no other declaration this time.
In second traverse it assigns the value 10 to a and interprets the settimeout and prints the value
In your third code,
Same as the second one except the fact that instead what “foo” was giving to the settimeout function, you wrote your callback function then n there itself.
By the time l it executed the setTimeout,
Each of your codes have the value for “a” in the global scope that they are accessing.

What is the lifetime of variables inside a self calling function in javascript

I've been trying to understand the following code:
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
Here add is assigned the return value of the anonymous self calling function -- that is the function function() { return counter += 1 }. Now the first time add() is called it returns 1 as expected. But the second time add() is called it returns 2.
My question is since counter is defined inside a function so wouldn't every time the function finishes execution counter should die? That is, after the first call to add() 1 will be displayed. Now we are out of that function so shouldn't counter forget it's previous value and be destroyed from the stack like automatic variables are?
What is the lifetime of variables inside a self calling function in javascript
The same as variables in any other kind of JavaScript function: They exist for as long as they can be referenced, which sometimes means long past the time the function that contains them returns.
Your counter variable continues to exist after the IIFE returns because the function it creates and returns (return function () {return counter += 1;}) is a closure over the variable. The variable will exist as long as that function exists.
More technically: Calling a function creates something called an execution context for that call, which has a variable enviroment object. Any function created during the call receives a reference to that outer variable environment object; that object, like all objects, exists as long as there's a reference to it, and so the functions keep the object alive. Variables are actually properties of that variable environment object, and so they exist as long as something references the object they're on. (This is the very simplified form.) While in theory the entire variable environment object is kept, in practice JavaScript engines are free to optimize if the effects of optimization aren't observable, so a variable that isn't actually used by the closure may (or may not) be released, depending on the engine and the code in the function.
Your IIFE can only be called once, so there can only be one counter, but it's common for a function creating a closure to be called more than once, in which case you have multiple variable objects, and multiple copies of the variables that are closed over.
Example:
function helloBuilder(name) {
var counter = 0;
return function() {
++counter;
display("Hi there, " + name + ", this is greeting #" + counter);
};
}
var helloFred = helloBuilder("Fred");
var helloMaria = helloBuilder("Maria");
helloFred(); // "Hi there, Fred, this is greeting #1"
helloFred(); // "Hi there, Fred, this is greeting #2"
helloMaria(); // "Hi there, Maria, this is greeting #1"
helloMaria(); // "Hi there, Maria, this is greeting #2"
helloFred(); // "Hi there, Fred, this is greeting #3"
function display(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
In the above, the function returned by helloBuilder closes over both its name argument and its counter variable. (Because arguments are also stored on the execution context's variable object.) So we can see that after calling it twice, there are two variable objects, each with its own name and counter, one referenced by each function we asked helloBuilder to create.

Why is this console log affected by a subsequent if statement?

Consider the following code:
var a = 'a';
function b() {
console.log(a);
if (!a) {
var a = 'b';
}
}
b();
Running b() prints undefined to the console. However, if you remove the if statement, or even simply remove the var keyword from the expression within the if statement so that you're redefining the outer a variable, the string a will be printed to the console as expected.
Can anyone explain this? The only cause I can think of is that this is a race condition, and the if statement is running just a tad faster than the console.log.
This is not a race condition - it's a language feature and is working as the designers of the Javascript language intended.
Because of hoisted variable definitions (where all variable definitions within a function scope are hoisted to the top of the function), your code is equivalent to this:
var a = 'a';
function b() {
var a;
console.log(a);
if (!a) {
a = 'b';
}
}
b();
So, the locally declared a hides the globally declared a and initially has a value of undefined until your if statement gives it a value.
You can find lots of discussion about this characteristic of the Javascript language by searching for "Javascript hoisting".
When you use var statement in a function, it will be creating a new variable which is local to that function.
All the variables declared in the function, will be moved to the top of the function, irrespective of the place where they are actually declared. This is called Hoisting.
The hoisted variables will have the value undefined, by default, till they are explicitly assigned a value.
It prints undefined as it is, because of the 3rd point.
In your case, you declared a variable a within the if block. Since the variables are hoisted, the declaration is moved to the top of the function. It has the same name as the outer variable. When you access a in the function, it first looks in the current scope if there is a variable by that name exists. It checks other scopes only if it is not found in local scope. So, the local a shadows the outer a. When you remove the var statement, there is no a in local scope, so the outer a is used. That is why it prints a.

why if statement isn't looking for a variable in global scope

I am trying to understand scoping in JS.Here i have an example which has a variable in global scope called check.It has a truthy value i mean 1.Then inside a function called main which doesn't have a variable called check but has an if statement which checks whether there is a check variable or not ,upon which it reassign another value to check variable.Then prints it out.if i use
if(check){}
it prints undefined.Here i have some questions:
1. check variable is declared in global scope.It means it has access everywhere.Then even if the IF statement fails it should print the globally assigned value which is 1 instead of undefined.Why it prints undefined instead of 1??
2. main function scope doesn't have a check variable.When if fails to find check inside main function's scope ,why it doesn't look for it in global scope??
(function(){
var check=1;
function main(){
if(check){
var check=10;
}
document.write(check);
}
main();
})();
JavaScript only has function scope and something called hoisting. Every variable declaration inside a function gets put at the beginning of the function. Thus, your code is equivalent to
var check=1;
function main(){
var check; // = undefined
if(check){ // block doesn't create scope
check=10;
}
document.write(check);
}
The local variable check shadows the outer variable check.
JavaScript will look up the chain for the most local variable it can find. Basically, local scope trumps global scope.
This is one of the potential pitfalls with global scope, and is why it should be avoided, since it creates clashes with local variables.

OO Javascript : Definitive explanation of variable scope

Can someone provide an explanation of variable scope in JS as it applies to objects, functions and closures?
Global variables
Every variable in Javascript is a named attribute of an object. For example:-
var x = 1;
x is added to the global object. The global object is provided by the script context and may already have a set of attributes. For example in a browser the global object is window. An equivalent to the above line in a browser would be:-
window.x = 1;
Local variables
Now what if we change this to:-
function fn()
{
var x = 1;
}
When fn is called a new object is created called the execution context also referred to as the scope (I use these terms interchangeably). x is added as an attribute to this scope object. Hence each call to fn will get its own instance of a scope object and therefore its own instance of the x attribute attached to that scope object.
Closure
Now lets take this further:-
function fnSequence()
{
var x = 1;
return function() { return x++; }
}
var fn1 = fnSequence();
var fn2 = fnSequence();
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn2())
Note: Replace WScript.Echo with whatever writes to stdout in your context.
The sequence you should get is :-
1 1 2 2 3 4 3 4
So what has happened here? We have fnSequence which initialises a variable x to 1 and returns an anonymous function which will return the value of x and then increment it.
When this function is first executed a scope object is created and an attribute x is added to that scope object with the value of 1. Also created in the same execution object is an anonymous function. Each function object will have a scope attribute which points to the execution context in which it is created. This creates what is know as a scope chain which we will come to later. A reference to this function is returned by fnSequence and stored in fn1.
Note that fn1 is now pointing at the anonymous function and that the anonymous function has a scope attribute pointing at a scope object that still has an x attribute attached. This is known as closure where the contents of an execution context is still reachable after the function it was created for has completed execution.
Now this same sequence happens when assigning to fn2. fn2 will be pointing at a different anonymous function that was created in a different execution context that was create when fnSequence was called this second time.
Scope Chain
What happens when the function held by fn1 is executed the first time? A new execution context is created for the execution of the anonymous function. A return value is to be found from the identifier x. The function's scope object is inspected for an x attribute but none is found. This is where the scope chain comes in. Having failed to find x in the current execution context JavaScript takes the object held by the function's scope attribute and looks for x there. It finds it since the functions scope was created inside an execution of fnSequence, retrieves its value and increments it. Hence 1 is output and the x in this scope is incremented to 2.
Now when fn2 is executed it is ultimately attached to a different execution context whose x attribute is still 1. Hence executing fn2 also results in 1.
As you can see fn1 and fn2 each generate their own independent sequence of numbers.
Variables not declared with var are global in scope.
Functions introduce a scope, but note that if blocks and other blocks do not introduce a scope.
I could also see much information about this by Googling Javascript scope. That's really what I would recommend.
http://www.digital-web.com/articles/scope_in_javascript/
Functions introduce a scope. You can declare functions inside other functions, thereby creating a nested scope. The inner scope can access the outer scope, but the outer can not access the inner scope.
Variables are bound to a scope, using the var keyword. All variables are implicitly bound to the top-level scope. So if you omit the var keyword, you are implicitly referring to a variable bound to the top level. In a browser, the top level is the window object. Note that window is it self a variable, so window == window.window

Categories

Resources