This question already has answers here:
Surprised that global variable has undefined value in JavaScript
(6 answers)
Closed 8 years ago.
I am new to closure concept of javascript. As i understood, By runtime call object stores reference to arguments, local variables and named parameters of function. With that, i tried to solve below snippet.
function a(){
var o=10;
function b(){
alert(o);
var o=20;
alert(o);
}
alert(o);
b();
}
a();
I expected the answer to be alert of 10, 20, 20, but it comes as 10, undefined, 20. Because b's call object stores reference to all local variables, first alert(o) in b should give 20, but why undefined is coming? Even if in b(), var o is defined at later point of time after alert(o), for that scenario shouldn't it access o from parent scope? Can somebody through some light on it!.
Because b's call object stores reference to all local variables
Yes. Local variables first, then parent scope variables.
first alert(o) in b should give 20, but why undefined is coming?
You've got two o variables here: One in the a scope, and one in the b scope. Due to hoisting, the variable declaration of var o=20 holds for the entire b scope, introducing an o variable (which is initially undefined) into the scope when b() is called.
Maybe this makes more sense:
function a(){
var o; // hoisted
function b(){ // hoisted
var o; // hoisted
alert(o);
o=20;
alert(o);
}
o=10;
alert(o);
b();
}
a();
Btw, you've not yet experienced a closure, whose distinguishing feature is that the parent scopes are persistet with the child function objects, even after the parent function has returned.
Related
I can't figure out why an unexecuted closure can capture the outer variables.
I do read about some articles about execute context, lexical environment, memory management, but none of these can solve my question:
function foo() {
var a = 1;
return function() {
console.log(a);
}
}
var f = foo() // line 7
// HERE variable a was been captured
f = undefined // line 10
// HEAE variable a was been released
When the engine execute to line7, the foo execution context was created above global execution context, but after line7 the closure was never been execute, so the closure execution context was never been created, so was the lexical environment. foo execution context was been popped up, the variable a will be released.
I can't find what's wrong with my point.
So why and when the variable in closure be captured?
function foo() {
var a = 1;
return function() {
console.log(a);
}
}
Function inside function are known as closure.
When one function has another function inside it, and say top level function has some data like 'a' in this case, then all the inner functions will get access to that data, this will happen only if inner function has some reference about those variables.
Let's say if you have 'b' variable beside 'a' and you are not using it anywhere in inner functions this will be simply ignored by javascript. 'Closure' will not hold this value like 'a'.
This is actually where closure gives devs power.Check out below example -
const test = (num1) => (num2) => console.log(num1*num2);//closure is in action here
var s = test(100)
s(2); // this will give output of 200
Hope this helps.
Thanks.
Here is a discussion on bugs.chromium that is related to your question. As per this , even when the else block never executed , reference to an outer object used in function returned by else block is created and stored in heap. It is never garbage collected. Refer to below discussion :-
https://bugs.chromium.org/p/chromium/issues/detail?id=315190
The key point is lexical scope:
Lexical scope is the scope model used by the JavaScript language, which differs to some other languages which use dynamic scope. Lexical scope is the scope defined at lexing time.
Considering this:
var a = 1
console.log(a)
console.log(b)
var b = 2
console.log(c)
You can get the result:
1
undefinded
ReferenceError: c is not defined
So, you can see how JavaScript handling the variables: all variable are defined at lexing time and assignment at runtime. This is what they called hoisting.
Back to the question: closures capture variables at lexing time in which js engine read your code and defined variable and bind them.
Read more about compilation at: https://v8.dev/blog/background-compilation
This question already has answers here:
Surprised that global variable has undefined value in JavaScript
(6 answers)
Closed 5 years ago.
if i declare variable at top with some value, then using that variable is showing undefined why?
var a = 100;
function test(){
console.log(a);
var a = 1000;
console.log(a);
}
test();
The output is undefined and 1000 why?
In your function, the local variable masks the global one.
var a = 100;
function test(){
console.log(a);
var a = 1000;
console.log(a);
}
test();
The fact that your var statement is in the function as well as global scope doesn't change anything. The global variable is masked for the whole function.
So, for the whole execution of the function, the global variable will reference the local one, and not the global one.
Outside of that function, though, the global variable will still exist
If you want to access the variable inside the function you can use
console.log(window.a);
It's because of the way JavaScript compiles the code.
Firsr it looks for declarations in the scope, then, if inner scopes are present, it looks for their own scope, in this case I'm pretty sure it's like the following:
Global scope will have a variable named a and a value of 100 assigned to it
There is a global function declaration named test, it needs its own scope, let's go for it
2.1. This scope will have a variable named a (uninitialized)
2.2 There is a call for the console object's function named log, it needs to have the variable named a, is that variable in this scope? Well, it looks like it is, but does not have a value assigned now so it is undefined.
2.3 NOW I have something to assign the variable, it's 1000, ok, let's continue.
2.4 There is a call for the console object's function named log, it needs to have the variable named a, is that variable in this scope? Well, it looks like it is, AND its value is 1000 console.log(a) => 1000
There is a call for the test function see 2.1
So, when you call the first console.log(a) the engine knows there is a local scope's variable named a, but it is not yet initialized, that's why you get undefined, then, in the second call, the local scope's a variable has a value of 1000 assigned to it, local scope is higher in hierarchy than parent scope so the value for the log will be 1000.
You might want to read about Hoisting of a javascript variable.
Because of hoisting, var a = 1000; is treated as var a; and a = 1000; as two different statements. The var a; statement, which is variable declaration, is moved to the top inside the function due to hoisting.
Now your function is as good as
var a = 100;
function test(){
var a;
console.log(a);
a = 1000;
console.log(a);
}
test();
var a; statement declares a local variable but is still undefined. So you get undefined on first console.log(a);.
To access the global variable learn how to use this like this.a.
I really hope this isn't a duplicate.
function a(){ b(); } // function a calls function b; but there's no function b in the global scope...
(function(){
// the purpose was to declare it later because it may collide with user-defined functions
var b = function(){ console.log('I am function b()'); };
a(); // doesn't work, obviously
a.call(this); // also doesn't work
a.apply(this, []); // doesn't work either
// neither works
var scope = { 'b': function(){ return b.apply(this,arguments); } };
with(scope){
a.call(scope);
}
// ... what works then?
}());
Simply put, function a() declared globally calls function b(). Function b() is not declared before a() and will not be part of the same scope.
So:
We cannot modify function a(), nor its location where is defined
We cannot declare b() in the same scope with a()
We also cannot var a = eval(a().toString()) or any likewise cheats
With pure scope handling, is this possible? And if it it's not, what else can we do?
Just trying to learn some JavaScript here that's all.
You can't do it. Variables local to a scope cannot be accessed outside that scope, that's the whole point of scoping. If you want to make the b() function visible outside the anonymous function, you need to assign it to an outer variable.
When you create a function object, it wraps all the enclosing functions and forms the closure. Later, whenever the object being used is not found in the local scope, the enclosing function objects will be searched.
In your case, a is declared in the global scope and there are no enclosing functions. When you invoke a from the IIFE, b will be searched within a itself and its enclosing functions and finally in the global scope, which is not found anywhere in that list of scopes. That is why it fails with
ReferenceError: b is not defined
Note: The important thing to be noted here is, when you invoke a function, the scope in which the function was defined will be searched, not where it is invoked from.
So, the answer is NO. Its not possible to do what you are trying to do.
Javascript Code
var d = function c() { console.log(c); };
d(); // function c() { console.log(c); };
c(); // Reference Error
I understand the concept of variable hoisting where variable declarations and function definitions are hoisted to top of the existing scope. Also function definition in function expressions are not hoisted.
So, above will be
var d;
d = function c() { console.log(c); };
d();
c();
Hence d is a reference to a named function c
on executing d() the function c is executed in global scope, where there is no variable or property named c. But still console manages to log function definition of c.
When I tried c() I got a reference error. [As I Expected]
Case 2 proves that there is no window property named c available
So, How did d() manage to print the c's definition on execution?
Does every function have its own definition in its local scope as a property?
Yes. A named function expression produces a variable corresponding to the function name within the scope of that function only.
Here's an excellent but lengthy article on the subject: http://kangax.github.com/nfe/
See also the relevant section of the ECMAScript 5 spec. It has a specific note about this.
What is the difference between these?
var a = 13;
this.b = 21;
document.write(a);
document.write(b);
For global code (code that is not part of any function), they are almost equivalent, both at the end create a property on the global object.
The difference is that a, which has been declared with the var statement, the Variable Instantiation process will use the global object as the Variable Object (1), and it will define that property as non-deleteable on it, e.g.:
var a = 13;
delete a; // false
typeof a; // "number"
Then, b since the this value in global code, points to the global object itself, will be also a global property, but this one can be deleted:
this.b = 21;
delete b; // true
typeof b; // "undefined"
Don't try the first snippet in Firebug, since the Firebug's console runs the code internally with eval, and in this execution context the variable instantiation process behaves differently, you can try it here.
(1) The Variable Object (VO) is an object that is used by the variable instantiation process to define the identifiers of FunctionDeclarations, identifiers declared with the var statements, and identifiers of function formal parameters, in the different execution contexts, all those identifiers are bound as properties of the VO, the Scope chain is formed of a list of VO's.
For global code, the VO is the global object itself, that's why a ends being a property of it. For function code, the VO (also known as the Activation Object for FunctionCode), is a new object is created behind the scenes when you invoke a function, and that is what creates a new lexical scope, in short I'll talk about functions.
Both a and this.b can be resolved simply as by a and b because the first object in the scope chain, is again the global object.
Also, I think is work knowing that the Variable Instantiation process takes place before than the code execution, for example:
alert(a); // undefined, it exists but has no value assigned to it yet
alert(b); // ReferenceError is thrown
var a = 13;
this.b = 21;
These differences may be trivial but I think is worth knowing them.
Now, if the code snippet you posted is within a function, it is completely different.
The a identifier, declared with the var statement in your example will be a local variable, available only to the lexical scope of the function (and any nested functions).
Keep in mind that in JavaScript blocks don't introduce a new scope, only functions do, and to declare a variable in that scope, you should always use var.
The this.b identifier will become a property bound to the object that is referred by the this value, but... What is this???.
The this value in JavaScript is implicitly set when you call a function, it is determined by how do you invoke it:
When you use the new operator, the this value inside the function, will point to a newly created object, e.g.:
function Test() {
this.foo = "bar";
}
var obj = new Test(); // a new object with a `foo` property
When you call a function that is member of an object, the this value inside that function will point to the base object, e.g.:
var obj = {
foo: function () {
return this == obj;
}
};
obj.foo(); // true
When you invoke a function without any base object, the this value will refer to the global object:
function test() {
return this == window;
}
test(); // true
The this value can be set explicitly, when you invoke a function using call or apply:
function test() {
alert(this);
}
test.call("hello world!"); // alerts "hello world!"
To understand in short, if you use these in a function then -
this.a; //will create a public property
var b; //will create a member variable
e.g. here is a Student class in javascript
var Student = function()
{
// Member variable
var studentId;
// Public property
this.Name = "";
}
for more - See Object Oriented Programming with JavaScript