What do closures mean exactly? [duplicate] - javascript

This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 8 years ago.
I've read about closures many times here.
But I'm really confusing to know exactly what do closure mean?
Is variable a closure ?
Or, is function is a closure ?
Or, both can be called a closure ?

A closure is a container for variables, it lets a function access variables from the scope where it was created even when it is called in a different scope.
Example:
function a() {
// a local variable
var x = 42;
function f() {
// use the local variable
return x;
}
// return the function f
return f;
}
// call a to get the inner function
var fx = a();
// call the inner function from out here
var y = fx();
// now y contains the 42 that was grabbed from the variable x inside the function
When the function f is created, it has a closure with it that contains the variable x from the scope where it was created. When the function is called from the global scope it can still access the variable x from the local scope as it is in the closure.
You could simulate the function of the closure by putting variables in an object, and send that along with the function, so that the function can use it later:
function a() {
// a "closure"
var o = { x: 42 };
function f(closure) {
// use the "closure"
return closure.x;
}
// return the "closure" and the function f
return { f: f, o: o };
}
// call a to get the inner function and the "closure"
var fx = a();
// call the inner function with the "closure"
var y = fx.f(fx.o);
// now y contains the 42 that was grabbed from the variable x in the "closure"
Note: The closure contains any identifer in the scope, so in the first example the closure for the function f also contains the identifier f which is the function. The function can call itself using the name f from anywhere, although the identifier f is local to the function a.

Related

TDZ in undeclared variables of function parameters [duplicate]

This question already has an answer here:
Scope of Default function parameters in javascript
(1 answer)
Closed 4 years ago.
When I try to run the foo function defined in this snippet I get a ReferenceError since b is not defined.
var b = 3;
function foo( a = 42, b = a + b + 5 ) {
// ..
}
foo()
This looks like a TDZ error because b has been defined in the outer scope but it's not yet usable in the function signature as a right-hand-side value.
This is what I think the compiler should do:
var b;
function foo(..) { .. }
// hoist all functions and variables declarations to the top
// then perform assignments operations
b = 3;
foo();
//create a new execution environment for `foo`
// add `foo` on top of the callstack
// look for variable a, can't find one, hence automatically create a
`var a` in the local execution environment and assign to it the
value `42`
// look for a `var b` in the global execution context, find one, use
the value in it (`3`) as a right-hand-side value.
This shouldn't raise a ReferenceError. Looks like this is not what happens here.
Can someone explain in what actually does the compiler do and how it processes this code?
On every function call, the engine evaluates some prologue code, which contains formal parameters, declared as let vars and initialized with their actual values or default expressions, if provided:
var b = 3;
function foo( ) {
let a = <actual param for a> OR 42;
let b = <actual param for b> OR a + b + 5;
// ..
}
Since b in a function is lexical (let), it's not possible to access its value before initialization. Hence the ReferenceError.
Note that this is a call-time error, so the following compiles fine:
var b = 1
function foo(b=b) {
console.log(b)
}
The error happens when you actually call the function:
var b = 1
function foo(b=b) {
console.log(b)
}
foo()
and only when the engine actually evaluates the faulty default expression:
var b = 1
function foo(b=b) {
console.log(b)
}
foo(7)
ECMA standard reference: FunctionDeclarationInstantiation, p.21:
For each String paramName in parameterNames, do
...Perform ! envRec.CreateMutableBinding(paramName, false).
The function arguments somewhat works like 'let'.
We cannot access variable created using 'let' before they are declared .i.e variables created using 'let' are not hoisted.
This happens because if the we are declaring the variable in local scope , it cannot access the global scope variable(Unless 'this' is used )
Your code can be fixed by this -
var b = 3;
function foo( a = 42, b = a + this.b + 5 ) {
// default binding. In this case this.b = global var
}
foo()
you can also see this error if you do this.
let variable = variable;

Why is non-static variable behaving like static?

function emergency() {
var ambulance = 100;
var callAmbulance = function() { alert(ambulance); }
ambulance++;
return callAmbulance;
}
var accident = emergency();
accident(); // alerts 101
I am referring to the variable 'ambulance'.
When I call accident(); it should call emergency() which should use the declared variable 'ambulance' [considering the global scope thing in javascript, still it could set the value to global] but its using old value 101 instead of setting again back to 100 - behaving more like static var.
What's the Explanation?
What you have there is called a closure. It means a function can access variables declared in outer functions (or in the global scope). It retains access even after the 'parent' function has returned. What you need to understand is that you don't get a copy. The changes performed on that variable are visible to your inner function, which in theory means you could have multiple functions sharing access to the same variable.
function f () {
var x = 0;
function a() { x += 1; }
function b() { x += 2; }
function show() { console.log(x); }
return {a:a, b:b, show:show};
}
var funcs = f();
funcs.a();
funcs.b();
funcs.show(); // 3
One thing to be aware of is that a subsequent call to f will create a new scope. This means a new x variable will be created (new a, b, show functions will be created as well).
var newFuncs = f();
newFuncs.a();
newFuncs.show(); // 1
funcs.a();
funcs.show(); // 4
So, how do you get a copy? Create a new scope.
function g () {
var x = 0;
var a;
(function (myLocal) {
a = function () { myLocal += 1; }
}(x));
x += 200;
return a;
}
JS only has pass-by-value so when you call the anonymous function, the xvariable's value will be copied into the myLocal parameter. Since a will always use the myLocal variable, not x, you can be certain that changes performed on the x variable will not affect your a function.
If, by any chance, you're coming from a PHP background you are probably used to do something like
use (&$message)
to allow modifications to be reflected in your function. In JS, this is happening by default.
You are creating a function definition which is not compiled at this time:
var callAmbulance = function() { alert(ambulance); }
And before you are sending it to the called function, you are incrementing the num:
ambulance++;
And then you are sending it to the called function:
return callAmbulance;
But whether you are sending it there or not, it doesn't matter. The below statement executes or compiles the function:
var accident = emergency();
And this takes in the current ambulance value which is 101 after the increment. This is an expected behaviour in creating function but not executing it. Please let me know, if you didn't understand this behaviour. I will explain it more clearly.

Access local variable inside a callback function

var inner = function() { console.log(x); }
// test 1
(function(cb) { var x = 123; cb(); })(inner);
// test 2
(function(cb) { var x = 123; cb.apply(this); })(inner);
// test 3
(function(cb) { var x = 123; cb.bind(this)(); })(inner);
// test 4
(function(cb) { cb.bind({x: 123})(); })(inner);
All tests result in:
ReferenceError: x is not defined
Do someone know how it is possible to access 'x' as a local variable inside the callback?
Fact: when you do var inner = function() { console.log(x); } in your first line, x is not defined. Why? Because, inside your inner function, there's no local declaration of x (which would be done with var x = something). The runtime will then look up in the next scope, that is the global scope. There isn't, also, a declaration of x, so x is also not defined there.
The only places where there is a variable called x are inside each one of your 4 IIFEs following. But inside the IIFEs, each x is a different variable, in a different scope. So, if what you want is to console.log() the x defined inside each IIFE, you are taking the wrong approach.
Keep in mind that, when you define inner, you are capturing the environment inside the function's closure. It means that, whatever value could x have there (in the declaration of the function), would be the available value to the x variable later, when the inner function would be used. The fact that your x there is not defined is only an accessory, and is not what is causing the undesired behavior.
So, what happens is that when you call your inner function inside any of your IIFEs, the x referred to inside the inner function declaration is a captured value of what x had as a value when the function was defined, not the value that x has now in the scope where the function is currently being called. This is what is called lexical scope.
To solve this, you would have to pass the value that you want to console.log() inside the inner function as a parameter to the inner function, as so:
var inner = function(x) { console.log(x); }
// test 1
(function(cb) { var x = 123; cb(x); })(inner);
The only way to access the local variable x in the callback, is to pass it as an argument:
var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb(x); })(inner);
OR
var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb.apply(this,[x]); })(inner);
OR
var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb.call(this,x); })(inner);
FURTHER
Because JS is lexically scoped, trying to reference the local variable after the anonymous function has finished executing is impossible by any other means. If you don't pass it as an argument to make it available elsewhere, JS will see it as non-reachable and it will be eligible for garbage collection.
You could redefine the callback function in the current scope:
var inner = function() { console.log(x); }
(function(cb) { var x = 123; eval('cb = ' + cb.toString()); cb(); })(inner);
// or
(function(cb) { var x = 123; eval('(' + cb.toString() + ')')(); })(inner);
This will not work if the function relies on anything in the scope in which it was originally defined or if the Javascript file has been minified. The use of eval may introduce security, performance, and code quality issues.
Have you tried using events? Emit an event inside the anonymous function, then subscribe to it in your own function somewhere else that carries out your logic.

Minimum viable JavaScript closure

The top answer on Stack Overflow regarding JavaScript closures defines them as (paraphrase):
A function that simply accesses variables outside of your immediate lexical scope that are not deallocated after the function returns.
Based strictly on this definition it seems like we can reduce the minimum viable closure (that does something useful) to a function containing no local variables that alters something in the global scope:
var x = 0;
function foo() {
x = x + 1;
return x;
}
foo(); // returns 1
foo(); // returns 2, et cetera
However, usual examples contain nested functions and variables that are "enclosed". Is this example a closure (or perhaps the global scope is now the closure)? Or is the definition incomplete?
Thanks!
No, because you simply don't use a closure here, there's only one scope, the global one, you're just using a global variable.
The definition you cite is ambiguous there :
after the function returns
In this definition, the "function" which "returns" is the one whose scope holds the variable, that is the external one. As there's no outer function, and the global scope never ends, there's no closure.
A closure would be like this :
var foo = (function(){
var x = 0;
return function() {
x = x + 1;
return x;
}
})(); // the function returns but x keeps being usable by the inner function
foo(); // returns 1
foo(); // returns 2, et cetera
And a less useless closure would be like this :
function makeFoo(){
var x = 0;
return function() {
x = x + 1;
return x;
}
}
var foo1 = makeFoo(), foo2 = makeFoo();
foo1(); // returns 1
foo2(); // returns 1
foo1(); // returns 2, et cetera
Yes, it is a closure. In the top answer, it actually provides a simplest closure example:
var a = 10;
function test() {
console.log(a); // will output 10
console.log(b); // will output 6
}
var b = 6;
test();
This is basically identical to your example, the scope of the function definition just happens to be the same as the parent of execution context.
When a Javascript function is invoked, a new execution context is created. Together with the function arguments and the parent object, this execution context also receives all the variables declared outside of it (in the above example, both 'a' and 'b').
You can actually use a new scope to replace the global scope in your example:
(function(){
var x = 0;
function foo(){
x = x + 1;
console.log(x);
}
foo(); // output 1
foo(); // output 2
})();

Lexical scope/closures in javaScript

I understand functions in 'js' have lexical scope (i.e. functions create their environment (scope) when they are defined not when they are executed.)
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined
When I run just 'f()' it returns the inner function. Which I get, that's what 'return' does!
function f() {
var b = "barb";
return function() {
return b;
}
}
console.log(b); //ReferenceError: b is not defined
Why do you get 'ReferenceError: b is not defined?'
But doesn't the inner function above have access to it's space, f()'s space etc. Being that 'b' is being returned to the global space, wouldn't the console.log() work?
However when I assign 'f()' to a new variable and run it:
var x = f();
x();// "barb"
console.log(b); //ReferenceError: b is not defined
This returns 'b' which is "barb", but when you run console.log() again you'll get 'ReferenceError: 'b' is not defined'; Isn't 'b' in the global scope now since it has been returned? SO why didn't 'x()' also return the inner function just like 'f()' did?
You, my friend, are thoroughly confused. Your very first statement itself is wrong:
functions create their environment (scope) when they are defined not when they are executed
Actually it's the opposite. Defining a function doesn't create a scope. Calling a function creates a scope.
What's a scope?
To put it simply, a scope is the lifespan of a variable. You see, every variable is born, lives and dies. The beginning of a scope marks the time the variable is born and the end of the scope marks the time it dies.
In the beginning there's only one scope (called the program scope or the global scope). Variables created in this scope only die when the program ends. They are called global variables.
For example, consider this program:
const x = 10; // global variable x
{ // beginning of a scope
const x = 20; // local variable x
console.log(x); // 20
} // end of the scope
console.log(x); // 10
Here we created a global variable called x. Then we created a block scope. Inside this block scope we created a local variable x. Since local variables shadow global variables when we log x we get 20. Back in the global scope when we log x we get 10 (the local x is now dead).
Block Scopes and Function Scopes
Now there are two main types of scopes in programming - block scopes and function scopes.
The scope in the previous example was a block scope. It's just a block of code. Hence the name. Block scopes are immediately executed.
Function scopes on the other hand are templates of block scopes. As the name suggests a function scope belongs to a function. However, more precisely, it belongs to a function call. Function scopes do not exist until a function is called. For instance:
const x = 10;
function inc(x) {
console.log(x + 1);
}
inc(3); // 4
console.log(x); // 10
inc(7); // 8
As you can see every time you call a function a new scope is created. That's the reason you get the outputs 4, 10 and 8.
Originally, JavaScript only had function scopes. It didn't have block scopes. Hence if you wanted to create a block scope then you had to create a function and immediately execute it:
const x = 10; // global variable x
(function () { // beginning of a scope
const x = 20; // local variable x
console.log(x); // 20
}()); // end of the scope
console.log(x); // 10
This pattern is called an immediately invoked function expression (IIFE). Of course, nowadays we can create block scoped variables using const and let.
Lexical Scopes and Dynamic Scopes
Function scopes can again be of two types - lexical and dynamic. You see, in a function there are two types of variables:
Free variables
Bound variables
Variables declared inside a scope are bound to that scope. Variables not declared inside a scope are free. These free variables belong to some other scope, but which one?
Lexical Scope
In lexical scoping free variables must belong to a parent scope. For example:
function add(x) { // template of a new scope, x is bound in this scope
return function (y) { // template of a new scope, x is free, y is bound
return x + y; // x resolves to the parent scope
};
}
const add10 = add(10); // create a new scope for x and return a function
console.log(add10(20)); // create a new scope for y and return x + y
JavaScript, like most programming languages, has lexical scoping.
Dynamic Scope
In contrast to lexical scoping, in dynamic scoping free variables must belong to the calling scope (the scope of the calling function). For example (this is also not JS - it doesn't have dynamic scopes):
function add(y) { // template of a new scope, y is bound, x is free
return x + y; // x resolves to the calling scope
}
function add10(y) { // template of a new scope, bind y
var x = 10; // bind x
return add(y); // add x and y
}
print(add10(20)); // calling add10 creates a new scope (the calling scope)
// the x in add resolves to 10 because the x in add10 is 10
That's it. Simple right?
The Problem
The problem with your first program is that JavaScript doesn't have dynamic scoping. It only has lexical scoping. See the mistake?
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined (obviously - f2 can't access the `a` inside f1)
Your second program is a very big mess:
function f() {
var b = "barb";
return function() {
return b;
}
}
console.log(b); //ReferenceError: b is not defined
Here are the mistakes:
You never called f. Hence the variable b is never created.
Even if you called f the variable b would be local to f.
This is what you need to do:
function f() {
const b = "barb";
return function() {
return b;
}
}
const x = f();
console.log(x());
When you call x it returns b. However that doesn't make b global. To make b global you need to do this:
function f() {
const b = "barb";
return function() {
return b;
}
}
const x = f();
const b = x();
console.log(b);
Hope this helped you understand about scopes and functions.
You get, "ReferenceError: b is not defined" because "b" is not defined where your console.log() call is. There's a "b" inside that function, but not outside. Your assertion that "b is being returned to the global space" is false.
When you invoke the function returned by your "f()" function, that will return a copy of the value referenced by that closure variable "b". In this case, "b" will always be that string, so the function returns that string. It does not result in the symbol "b" becoming a global variable.
But doesn't the inner function above have access to it's space, f()'s space etc.
Yes it has. It accesses the b variable and returns its value from the function.
Being that 'b' is being returned to the global space
No. Returning a value from a function is not "making a variable available in the caller scope". Calling the function (with f()) is an expression whose result is the value that the function returned (in your case, the unnamed function object). That value can then be assigned somewhere (to x), a property of it can be accessed or it can be discarded.
The variable b however stays private in the scope where it was declared. It is not [getting] defined in the scope where you call console.log, that's why you get an error.
What you want seems to be
var x = f();
var b = x(); // declare new variable b here, assign the returned value
console.log( b ); // logs "barb"
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined
f2(); does not knows about the a,because you never passed 'a' to it,(That's Scope are
created when the functions are defined).Look function f2() would have been able to acess
a if it was defined inside f1();[Functions can access the variables in same scope in
which they are "DEFINED" and NOT "CALLED"]
function f() {
var b = "barb";
return function(){
return b;
}
}
console.log(b);
First of all You Need to Call f(); after executing f(); it would return another function
which needs to be executed. i.e
var a=f();
a();
it would result into "barb" ,In this case you are returning a function not the var b;
function f() {
var b = "barb";
return b;
};
console.log(f());
This would print barb on screen

Categories