I was explaining javascript closure to a friend like this:
function outer() {
var count = 0;
return (function(){
count++;
console.log(count);
})();
}
I was trying to show him that how does this 'count' variable is stored when the outer function is executed.
So I tried doing this in the javascript console and wanted to show him that when you do this in the console
outer(); // prints out 1
outer(); // calling again prints 2
outer(); // prints out 3
but actually this happened
outer(); // printed 1
outer(); // printed 1 again
outer(); // again 1
I don't understand whats going wrong here. Can someone guide me.
Thanks to #elclanrs. This is the working code.
function outer() {
var count = 0;
return (function(){
count++;
console.log(count);
});
}
Now when i call this function and store it in a variable
var myouter = outer();
myouter();
// 1
// undefined
myouter();
// 2
// undefined
myouter();
// 3
// undefined
It is because your count is declared inside the function, so it is "private" to the function scope, so every time your function is called, the variable count will be created and initialized to 0 then your inner function, aka, closure increments it, that is why it prints 1, then when your closure returns, your count variable is garbage-collected because its scope ends there -- within the matching curly braces, try moving count to the outermost outside any function, then you will get what you want, then your count will become a global variable which is not good in production code because you dont want to taint your global pool, and create memory leak problem. Closures are basically just inner functions like in Java.
You set count=0 every time you call outer(). If you want count to be private, meaning outside global scope, then I would use a module pattern like this:
var counter = (function(c){
var count = 0;
c.outer = function(){
count++;
console.log(count);
};
return c;
}({} || counter))
counter.outer();
or you can simply have outer() return a function:
function outer() {
var count = 0;
return function(){
count++;
console.log(count);
};
}
var myo = outer();
myo();
myo();
myo();
Related
Im new to Javascript and I dont understand whats happening how the scope works in the following codes:
//Code n°1:
let num = 1;
function test(){
console.log(num);
}
test() //As I expected I get in console "1"
//Code n°2:
let num = 1;
function test(){
let num = 2;
console.log(num);
}
test() //As I expected I get in console "2"
But here is the problem:
//Code n°3:
let num = 1;
function test(){
console.log(num)
let num = 2;
console.log(num);
}
test() //I expected to get in console "1" and then "2" but instead I get an error.
When I run in my browser the code n° 3 Im getting this error:
Uncaught ReferenceError: can't access lexical declaration 'num' before initialization
If I look at code 1 and 2 I suppose that after running code 3 I will get in my console the number 1 and then number 2. But that isnt happening. Why?
Thank you so much!
The JavaScript exception "can't access lexical declaration `variable' before initialization" occurs when a lexical variable was accessed before it was initialized. This happens within any block statement, when let or const declarations are accessed before they are defined.
When the 'test function' is called, the function body gets executed. When it reaches to 'console.log(num)', it starts to search for the 'num variable declaration' (or 'num assignment' or 'num reassignment) in the test function scope. So it finds the variable declaration in the next line. The priority for searching for a variable is:
Current Scope
Closure
Scope Chain
So, when the variable declaration is found i the current scope, searching is not continued to scope chain. (It will not search for num variable in global scope.)
I guess this is the reason of the error, but as I am new to javaScript, I am not completely sure.
If you initialize the variable without redeclaring, it will work normally, now if you redeclar the variable, then this error will happen with let or var, because in the same scope, it is being called by the previous console.log().
It is not recommended that you re-declare let variables, if you need to, don't use the same in previous statement, note that if you comment on the first console.log(), the code will work again, this occurs exactly for the lifetime of the variable within this scope, in this case, let
let num = 1;
function test(){
console.log(num)
let num = 2;
console.log(num);
}
test()
Bacause in javascript functions and variables declared with var are hoisted, moved up to the top of the function/lexical block.
But let keyword respect the lexical flow. It pins variable where it is declared.
console.log try to access a variable that is declared bellow in the flow.
So move up manually your let declaration to be above de console.log or change it to var let num = 2; to let javascript engine move it above all automatically.
var num = 1;
function test(){
let num = 2;
console.log(num);
}
test()
or
var num = 1;
function test(){
console.log(num)
var num = 2;
console.log(num);
}
test()
or, to get access to global var num, which is shadowed by declarations from test's body, var or let, no matter
var num = 1;
function test(){
console.log(num)
//let num = 2;
console.log(num);
}
test()
I'm learning javascript by reading "Eloquent Javascript" and am confused by the "Closures" section in chapter 3 (Functions).
In previous sections I learned about arrow functions, and how they can be used as anonymous functions. My initial thoughts were that this is an anonymous function example and I am simply not familiar yet.
In particular, I am confused on what "() => local" does to/for return.
function wrapValue(n) {
let local = n;
return () => local;
}
let wrap1 = wrapValue(1);
let wrap2 = wrapValue(2);
console.log(wrap1());
// → 1
console.log(wrap2());
// → 2
Here is a link to the chapter:
Eloquent Javascript - Ch. 3 "Functions"
Thanks in advance!
In javascript function create scope. For example:
function scoped(){
let local = 10;
console.log(local) // this works local is within scope
}
scoped() // logs:
console.log(local) // error -- local doesn't exist out here.
Outside of scoped local doesn't exist.
A function inside a function has access to the entire scope. So this works:
function scoped() {
let local = 10;
function f() {
console.log(local) // this works local is within scope
}
f()
}
scoped()
But what happens if you return that function that references the scope of the function? It turns out that the inner function carries the whole scope with it. This is a closure:
function scoped(){
let local = 10;
function f(){
console.log(local) // this works local is within scope
}
return f
}
f = scoped()
f() // can still see local
// but nobody else out here can:
console.log(local) // still an error
This allows you to do some very slick things — an import one is that you can keep certain variables private, but still manipulate them with the closure.
For example here's a counter that doesn't require a variable in global scope:
function counter(){
let count = 0
return () => count++
}
let c = counter()
console.log(c()) // it can count but there's not count variable in scape
console.log(c())
console.log(c())
Doing this with a global count variable is messy and risks some other part of the code clashing with the global variable. Above, nothing other than the c function can access the counter. In fact you can make several independent ones:
function counter(){
let count = 0
return () => count++
}
let c = counter()
let d = counter()
console.log("c:", c()) // it can count but there's not count variable in scape
console.log("c:", c())
console.log("d:", d()) // d has it's own closure
console.log("d:", d())
console.log("c:", c())
There's a lot you can do with closures and they're important in Javascript. It's worth taking the time to really understand them.
function wrapValue(n) {
let local = n;
return () => local;
}
Is the same as writing (without the benefits of "this")
function wrapValue(n) {
let local = n;
return function() {
return local;
}
}
It's a function that returns another function that uses the passed parameters. This is called a Curry function
console.log(typeof wrapValue(2)); // prints "function"
console.log(wrapValue(2)()); // prints "2"
Here's a better example
function multiple(a) {
return (b) => a*b;
}
console.log([1,2,3,4].map(multiple(2)); // prints "[2,4,6,8]"
You can use curried functions very easily with Arrays
Over here, I am returning a function which is closed over the 'i' variable, creating a closure.
var myFunc = function(){
var i = 0;
function increment(){
return ++i;
console.log(i);
}
return increment
}
now If I assign this function to other variables like
var newFunc = myFunc();
var newFunc2 = myFunc();
calling any of them will result in
newFunc() // 1
newFunc() // 2
newFunc() // 3
newFunc2() // 1 ??
Where is the value of var i getting stored?
is it getting stored in the execution context of each function so that it can be changed only when we call that specific function.
I saw you define the variable i inside the
myFunc
which means that the scope of the variable i will be within that function. So whenever you call this function, it will create create its own i.
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
Here's some JavaScript:
linkElem.click(function () {
var data = linkElem.data();
alert(''+data.mls + ' ' + data.id);
});
It works.
linkElem is a local variable that I create in a loop inside a function. I assign some data to it with jQuery's .data(). If I did not call .click(), linkElem would be reassigned during the loop and then recycled after the function returns. However, I have created an anonymous function which references linkElem. So I am no longer sure what is going on.
My guess is that all of the anonymous functions and linkElems created during the loop are given UIDs of some kind and moved to persistent/global scope. Is this correct? Gratuitous detail would be much appreciated.
Yes, your description is pretty close. The local storage for a Javascript function call is just a block of memory allocated for local variables. If you "capture" that by creating another function inside a called function, then the storage is retained and the local variables carry on with their lives, unaware that the function that gave them birth might be long dead.
It's important to keep in mind that only functions create such storage — things like brace-enclosed loop bodies are not separate storage areas. Thus a common error is to declare a variable in a function and re-use it among several functions created in a loop. That's not inherently wrong, but the effect can be surprising:
function whatever() {
for (var i = 0; i < 3; ++i) {
setTimeout(function() { alert(i); }, 5000);
}
}
If you run that, you'll see three alerts that all say "3". Why? Because they all share the same "i" variable. You can avoid that by introducing another function layer:
function whatever() {
for (var i = 0; i < 3; ++i) {
setTimeout((function(private_i) { return function() { alert(private_i); }; })(i), 5000);
}
}
The "wrapper" function is just there to provide a local variable (the parameter "private_i") whereto the loop variable "i" can be copied.
However, I have created an anonymous function which references linkElem. So I am no longer sure what is going on.
It still gets reassigned, unless you are wrapping it in another level of scope (NB: another function).
Consider the following:
for (var j = 0;j < 10;j += 1) {
arrayOfLinks[j].onclick = function () {
alert(j);
};
}
In this case, all of those links would alert 10 when clicked, because j is outside of the scope and is being updated.
If you're creating linkElem in the same way, you are likely to only get the result of the last linkElem in the loop.
This is a better way:
linkElem.click(function () {
var data = $(this).data(); // no longer dependent on `linkElem` reference
alert(''+data.mls + ' ' + data.id);
});
Please refer to this How do JavaScript closures work?
This may help you understanding closures.
Whenever you see the function keyword within another function, the inner function has access to variables in the outer function.
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp));
}
bar(10);
}
foo(2)
This will always alert 16, because bar can access the x which was defined as an argument to foo, and it can also access tmp from foo.
That is a closure. A function doesn't have to return in order to be called a closure. Simply accessing variables outside of your immediate lexical scope creates a closure.
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
var bar = foo(2); // bar is now a closure.
bar(10);
The above function will also alert 16, because bar can still refer to x and tmp, even though it is no longer directly inside the scope.
However, since tmp is still hanging around inside bar's closure, it is also being incremented. It will be incremented each time you call bar.
The simplest example of a closure is this:
var a = 10;
function test() {
console.log(a); // will output 10
console.log(b); // will output 6
}
var b = 6;
test();
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').
It is possible to create more than one closure function, either by returning a list of them or by setting them to global variables. All of these will refer to the same x and the same tmp, they don't make their own copies.
[you]: Fascinating, tell me more!
Here the number x is a literal number. As with other literals in JavaScript, when foo is called, the number x is copied into foo as its argument x.
On the other hand, JavaScript always uses references when dealing with Objects. If say, you called foo with an Object, the closure it returns will reference that original Object!
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + tmp);
x.memb = x.memb ? x.memb + 1 : 1;
alert(x.memb);
}
}
var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);
As expected, each call to bar(10) will increment x.memb. What might not be expected, is that x is simply referring to the same object as the age variable! After a couple of calls to bar, age.memb will be 2! This referencing is the basis for memory leaks with HTML objects.