In my naive concept, a closure is simply a function return by another function, which preserve the scope of the outer function after it returns:
var factory = function(y){
var x = 2;
return function(){
console.log(x+y);
}
}
var closure1 = factory(2);
closure1(); // output 4
var closure2 = factory(10);
closure1(); // output 4
closure2(); // output 12
Though I do not understand why adding event handler in loop will create closures? (As shown in MDN) The event handler does not explicitly be returned, this is not the concern in this problem.
Then I came across another page, and at around Code snippet #2:, it said
The onclick function would create a closure if it referenced variables in its scope, but it doesn’t.
Does that mean that in the loop
nodes[i].onclick = function () { return false; }; is not closures
But if I changed it into
nodes[i].onclick = function () { console.log(i); return false; };
Then it becomes closure?
Combined the parts above, my concept to create a closure are
It needs to be a function returned in another function, or the callback function which attached in another function
The inner function MUST somehow access outer function's scope
Is it true that a closure is created iff 1 & 2 are satisfied?
a closure is simply a function return by another function, which preserve the scope of the outer function after it returns
Close.
It is a function which still has references pointing to it after the function that it was created inside has finished.
Returning it is one way to preserve a reference to it.
Though I do not understand why adding event handler in loop will create closures?
The reference is passed to the event handling code. This preserves it after the function which passed it there has finished.
Does that mean that in the loop …
Yes, it does.
It needs to be a function returned in another function, or the callback function which attached in another function
No. The reference can go anywhere, so long as it is preserved.
var obj = {};
function create() {
var foo = 1;
obj.bar = function() {
console.log(foo++);
};
}
create();
obj.bar();
obj.bar();
obj.bar();
obj.bar();
The inner function MUST somehow access outer function's scope
Yes
Related
Can someone explain why in the following function, I am able to pass an argument to a nested function? My understanding is that it has to do something with closures and scope(which I thought I had a decent understanding of), but I can seem to follow how exactly this argument is being passed.
The below function outputs 1,2 respectively. But how is the return statement doThis() getting the argument/parameter for "a"? I cant figure where/how this is accessed/passed.
function doSomething(){
var b = 1;
return function doThis(a){
console.log(b);//1
console.log(a);//2
}
}
var exec = doSomething();
exec(2);
The function doSomething() returns another function so when you execute
var exec = doSomething();
You can think of that exec as containing the following function
function doThis(a){ // <- takes an argument
console.log(1); // comes from the b argument in the outer scope
console.log(a); // not set yet
}
Thus when you call exec(2) you are actually calling doThis() with an argument 2 which becomes the value of a.
This is a slightly simplified version. To expand on that, the doSomething() function is described as closing over doThis() creating a closure. Conversely, the function doThis() is closed over or inside a closure. The closure itself is simply a limited state around the function:
function doSomething(){ // --> defines the closure
var b = 1; // variable only visible within doSomething()
return function doThis(a){ //<--> function has access to everything in doSomething(). Also defines another closure
console.log(b); // --> accesses the OUTER scope
console.log(a); // <-- comes from the INNER scope
} // <-- end INNER scope
} // --> end OUTER scope
When you execute doSomething() the returned result still retains access to the scope within it, this is why doThis() has access to the value b - it's simply reachable for it. It's similar how you can do
var foo = 40;
function bar(value) {
return foo + value;
}
console.log(bar(2));
Only in this instance any other code will have acces to foo as it's a global variable, so if you do foo = 100 in a different function, that will change the output of bar(). A closure prevents the code inside from being reachable from outside the closure.
When you assign var exec = doSomething();, exec is basically writing:
var doSomething = function(a) {
console.log(b);
console.log(a);
}
It became its own function. So passing in 2 like so exec(2) works like any normal function except that it has the variable b available to it because of the closure.
How the variable 'str2' is available inside the callback method passed to display method?
str2 should be visible only inside function 'name'.
a = {
display: function (n){
console.log("I am inside display method");
n();
}
}
function name(a,str2)
{
a.display(function (){
console.log(str2);
})
}
name(a, 'ddd');
Variable scoping in Javascript is hierarchical. Lower scopes have access to all variables of all higher scopes. Here's an example:
function outer() {
var foo = 2;
function inner() {
console.log(foo); // 2
}
}
It doesn't matter if a variable is passed as a parameter or if it was defined as a local var.
Yes str should be visible only inside function 'name' yes it is working same you said, in JavaScript function declarations loads before any code is executed, and scope depend on execution context
in your code scope of str2 is inside name() function and you call a.display() within this scope (within scope of name()) that's why str2 available inside display() at the time of execution.
To evaluate name(a, 'ddd'), the compiler will create a new stack frame and place two slots on it, one a, which will be a reference to the global object of the same name, and str2, which will contain the string literal 'ddd'. Then the body will be evaluated.
In the body, to evaluate a.display(function(){...}), the value of a.display will be resolved to the function with parameter n. To evaluate n(function(){...}), a new stack frame will be created with n assigned to the closure that results from evaluating the anonymous callback (a closure being a combination of a pointer to the static scope of the function and the compiler generated code for the function itself). Then the body of the a.display function will be evaluated.
In the body, the console.log will be called with the given string. Then the callback n() will be evaluated. Since n doesn't take any parameters, it will just be evaluated in the topmost stack frame, so when the time comes to evaluate console.log(str2), str will not be found on the current stack frame, so the compiler will follow the scope chain all the way to the frame where we bound 'ddd' to str and a to the function.
That's a pretty long answer to your simple question. I'll try to shorten it later. Also, corrections are welcome, as I'm being very hand-wavy with the evaluation process.
In Javascript the variable declared on a certain scope is available in every inner scope. In this case it's a concept called "closure". This answer might give you good insight about scoping in Javascript: What is the scope of variables in JavaScript?
Hope this simple example can help you understand its usefulness:
function counter () {
var votes = 0;
this.upvote = function() { votes++; }
this.downvote = function() { votes--; }
this.getValue = function() { return votes; }
}
var counter1 = new counter();
counter1.upvote();
console.log(counter1.getValue()) // Prints 1
counter1.upvote();
counter1.upvote();
console.log(counter1.getValue()) // Prints 3
I've really looked all over for this and haven't found an answer that really explained this well...
I know how to access a global variable from within a function.
myGlobalVariable = [];
function myFunction() {
myGlobalVariable.push("somedata");
}
Now how do I access a variable one step up on the scope chain if it isn't global?
myGlobalVariable = [];
function myFunction() {
var notGlobalVariable = "somedata";
var myOtherFunction = function() {
myGlobalVariable.push(notGlobalVariable); // This is what I'd like to be able to do.
}
}
I know I could do something like
var notGlobalVariable = "somedata";
var myOtherFunction = function(arg) {
myGlobalVariable.push(arg);
}
myOtherFunction(notGlobalVariable);
But calling the function that way only works if I have the value of notGlobalVariable readily available. I'd like do be able to globally call the function and have it always use the value originally held by notGlobalVariable without having to pass that value in.
Edit
Alright, I kinda jumped the gun on this one. I though I was having a big variable scope issue, but apparently my issue was that in my specific code I was using the variable name arguments in place of notGlobalVariable, and as I should have known, arguments is shadowed and refers to the arguments passed in. I changed the name to args and it works fine. Sorry!
JavaScript does that automatically by creating closures.
Every function creates its own scope.
Scopes are nested, since functions can be defined within functions.
Every new nested scope ("function") can see all the variables that were defined in any parent scope at the point of its (i.e that new function's) creation. This is called a closure.
Every variable from any parent scope is "by reference" - child scopes ("functions") always see their current values.
The point in time when the function runs does not matter, only the point in time when it was declared (see first example).
The scope where a function runs in does not matter, only the scope a function was defined in (see second example).
Here
var myGlobalVariable = [];
// define function => creates closure #1
function myFunction() {
var notGlobalVariable = "somedata";
// define function => creates closure #2
var myOtherFunction = function() {
myGlobalVariable.push(notGlobalVariable);
}
// execute function
myOtherFunction();
}
myFunction(); // myGlobalVariable will be ["somedata"]
you create two scopes:
myFunction can see myGlobalVariable
the anonymous function stored in myOtherFunction can see myGlobalVariable and notGlobalVariable.
Now assume a small change:
var myGlobalVariable = [];
// define function => creates closure #1
function myFunction(callback) {
var notGlobalVariable = "somedata";
// define function => creates closure #2
var myOtherFunction = function() {
myGlobalVariable.push(callback());
}
// execute function
myOtherFunction();
}
// define function => creates closure #3
function foo() {
var thisIsPrivate = "really";
// define function => creates closure #4
return function () {
return thisIsPrivate;
}
}
myFunction(foo()); // myGlobalVariable will be ["really"]
You see that the callback function has access to thisIsPrivate because it was defined in the right scope, even though the scope it is executed in cannot see the variable.
Likewise the callback function will not be able to see notGlobalVariable, even though that variable is visible in the scope where the callback is executed.
Note that you always must use var on any variable you define. Otherwise variables will be silently global which can and will lead to hard to fix bugs in your program.
You do have access to notGlobalVariable inside of myOtherFunction. However you're only assigning myOtherFunction and never invoking it. Note that you'll have to invoke myOtherFunction inside of myFunction.
function myFunction() {
var notGlobalVariable = "somedata";
var myOtherFunction = function() {
myGlobalVariable.push(notGlobalVariable); // This is what I'd like to be able to do.
}
//Invoke myOtherFunction()
myOtherFunction()
}
Yes, you can - in javascript everything is possible - here is the fiddle http://jsfiddle.net/AZ2Rv/
myGlobalVariable = [];
function myFunction() {
var notGlobalVariable = "somedata";
// The following assigns a function to a variable
var myOtherFunction = function() {
myGlobalVariable.push(notGlobalVariable);
}
// The following line was missing in the code in the question so the function
// was never called and `notGlobalVariable` wasn't pushed into `myGlobalVariable`
myOtherFunction();
}
// And just to test if it works as expected
myFunction();
alert(myGlobalVariable[0]);
The problem of the OP laid actually in the code he didn't posted, but this sample code answers the original question - closures still work in javascript as expected.
I am binding a function to an html element.
there is some data in loop which is changing on each iteration
data = {
networkId: networkId,
network_avatar: network_avatar,
network_user_name: network_user_name,
}
Here I am binding it:
$("#element"+i).bind(function(){
change(data);
}
The function is:
function change(data){
console.log(data);
}
There should be the different data in data variable on each iteration.
But the it always contains the content of last iteration.
Why jQuery changes the data that is already binded with change() function
First of all, don't use global variables named "data" or "window" or anything else like this. If the declaration of your variable data is somewhere in vision area use "var" bareword.
When the event handler is called, it calls the "change" function and sending the current value of data in it. What you need, is to declare own data for each handler. And you should use "var" for it. Like:
$("#element"+i).bind(function(){
var currentDataValue = new CopyData(data);
change(currentDataValue);
}
function CopyData(object) {
var data = {};
for (var val in object)
data[val] = object[val];
return data;
}
I guess it should help. But i'm not too sure.
Try nesting the function within another function to create a closure. The trick with a closure is that you must have two nested functions, an inner function and an outer function. The inner function will possess a copy of the outer functions variables & parameters, in a sense inheriting its scope. In my example bindClick serves as the outer function, while the anonymous function within the call to $.click() serves as the inner function. This results in the anonymous inner function retaining the data object passed into the bindClick() method as a parameter. When we run this in a loop we essentially end up with 10 closures that remember the data object they were created with.
Live Example: http://jsfiddle.net/cDwEk/1/
function bindClick(data){
$("#element" + data.myProp).click(function(){
//anonymous function will remember state of outer functions variables.
alert(data.myProp);
});
}
//ForLoop
for(var i = 0; i < 10; i++){
var data = {myProp:i};
//Pass function to another function to create closure.
bindClick(data);
}
The following program returns "local" and, according to the tutorial Im reading, it is designed to demonstrate the phenomenon ofclosure`
What I don`t understand is why, at the end, in order to call parentfunction, it assigns it to the variable "child" and then calls "child."
Why doesn`t it work by just writing parentFunction(); at the end?
var variable = "top-level";
function parentFunction() {
var variable = "local";
function childFunction() {
print(variable);
}
return childFunction;
}
var child = parentFunction();
child();
parentFunction() returns another function which you assign to var child. Then, you call child() to invoke the function returned by the call to parentFunction().
Running just parentFunction(); at the end wouldn't do anything useful because you would just discard its return value which is a function. But this would work:
parentFunction()();
See this fiddle: http://jsfiddle.net/USCjn/
Update: A simpler example:
function outer() { // outer function returns a function
return function() {
alert('inner function called');
}
}
x = outer(); // what is now in x? the inner function
// this is the same as saying:
// x = function() {
// alert('inner function called');
// }
x(); // now the inner function is called
See this fiddle: http://jsfiddle.net/bBqPY/
Functions in JavaScript can return functions (that can return functions (that can return functions ...)). If you have a function that returns another function then it means that when you call the outer function what you get is the inner function but it is not called yet. You have to call the value that you got as a function to actually run the body of the inner function. So:
x = f();
means - run a function f and store what it returns (which may be a string, a number, an object, an array, or a function) in x. But this:
x = f()();
means - run a function f, expect it to return a function and run that returned function as well (the second parentheses) and store in x what the returned function returned.
The function f here is a higher order function because it returns another function. Functions can also take another functions as arguments. One of the most powerful ideas of functional programming languages in general and JavaScript in particular is that functions are just normal values like arrays or numbers that can be returned and passed around.
You have to first grasp the idea of higher order functions to understand closures and the event system in JavaScript.
2016 Update
Note that currently this:
function outer() {
return function() {
alert('inner function called');
}
}
can be written as:
let outer = () => () => alert('inner function called');
using the ES6 arrow function syntax.
The amazing part about closures is that an inner function (in this case, childFunction) can refer to variables outside of its scope (in this case, variable). parentFunction doesn't return the result of childFunction, but an actual reference to the function!
This means that when you do the following...
var child = parentFunction();
...now, child has a reference to childFunction, and childFunction still has access to any variables it had when the function was created, even if they no longer exist.
In order to have parentFunction call childFunction, you'd need to change your code as follows:
From...
return childFunction;
To:
return childFunction();
Douglas Crockford (Pioneer of JSON, among other things) has a whole article devoted to closures, and scoping in javascript, and it would be well worth it to check out his other articles on javascript.
The point that is being demonstrated is that the function that was returned and assigned to child is still referencing the variable that was declared inside parentFunction instead of the one that was declared outside where child() is being invoked.
The only way to create a variable scope in javascript is in a function body. Normally the variable inside the parentFunction would have been discarded after the function returned.
But because you declared a function inside parentFunction that referenced variable in that scope and passed it out of parentFunction, the variable in the parentFunction is retained via the reference made in the new function.
This protects variable from outside manipulation except by functions that closed around it inside parentFunction.