I've read everything about js closures but can't understand the following code:
function main(condition){
var a;
if (condition){
a="aaa";
}
else
{
a="bbb";
return;
}
button.addEventListener("click", function(){ alert(a);});
}
main(true);
main(false);
After that click button. The result is:"aaa". Doest this mean that for nested function doesn't keep the reference to variables but copy them? Please explain.
The first time you run main, you assign "aaa" to a (which is a local variable) and then bind an event handler which reads that variable.
The second time you run main, you assign "bbb" to a (since this is a different invocation of the function, it is a different local variable). You do not bind an event handler that reads that variable since you return first.
When the click event fires, the function it runs is in the scope of the a from the first call, not the second call, so the value is "aaa".
I would say that this is what closures are all about. Closures are "internal functions" that retain access to the values of variables that were "valid" at the moment when the internal function was created even after the "outer function" returned.
Consider the following example:
var outerFunc = function(a) {
return function (x) {
return x+a;
}
} //the outer function returns a function
Now let's invoke the outer function and store the returned value in the variable newFunc:
var newFunc = outerFunc(15); //the outer function has been invoked, newFunc is a function
newFunc(1); //let's invoke the resulting "inner function"
The result will be 16. The inner function will always remember the value 15, even if you invoke the outer function with other argument values. This is how JavaScript works.
In your example with the event listener something very similar is happening. The inner function (with the alert) is registered as a reaction to the click event, and it always 'remembers' the value of a. When you press the button, this invokes this 'inner' function.
To get the behavior you may want, try:
var main = function () {
var a;
return function() {
if (condition){
a="aaa";
}
else
{
a="bbb";
return;
}
button.addEventListener("click", function(){ alert(a);});
};
}();
main(true);
main(false);
This works because it defines a in a way which persists across invocations of the function, which as another answerer pointed out, is the problem.
that is not a closure, its just a double call to a function, when its true it adds the event listener so that it prints 'aaa' but second time it isn't added an event, because it returns before adding it.
Related
I'm following a tutorial by Tyler McGinnis on execution contexts, call stacks and closures.
https://www.youtube.com/watch?v=Nt-qa_LlUH0&feature=emb_title
I'm a bit confused with the closure example. I understand a closure is when a function is inside another function. I also understand that the inner function has access to the parent functions arguments (As explained in the video).
My confusion is in the code below is when makeAdder(5) is invoked is the inner function not invoked aswell on the first invokation? Tyler appears to suggest makeAdder is popped off the call stack when first invoked just leaving the inner function untouched.
The second part I don't understand when we call add5(2) this is invoking makeAdder(5) no? How do we add 2 arguments when the parent function only accepts one?
If someone could walk it through step by step of how it's all invoked that would be great!
var count = 0;
function makeAdder(x) {
return function inner(y) {
return x + y;
}
}
var add5 = makeAdder(5);
console.log(add5); // what the call to makeAdder returns
count += add5(2);
console.log(count);
when makeAdder(5) is invoked, is the inner function not invoked as well on the first invocation?
No, it isn't. Only makeAdder is invoked at that time, and makeAdder is not making any calls itself. It merely returns an object, and that object happens to be a function. And returning a function is done without actually invoking it.
when we call add5(2) this is invoking makeAdder(5) no?
It is not invoking makeAdder(5). Earlier on add5 was the result of calling makeAdder(5), and so add5 is that inner function. The special thing happening here is that when you call add5, an "execution context" is restored, which represents the state of affairs inside makeAdder at the moment it returned the function. This practically means that when add5 (the inner function) references the x variable, it will find the value in x it had at the moment makeAdder had been called earlier on.
How do we add 2 arguments when the parent function only accepts one?
Indeed, when we call the parent function, the second argument is not known yet, and we don't need to know it at that moment, since the inner function is not yet executed at that moment. The important thing with the call of the parent function, is that we establish the value of x, which will "live on", even though it can only be accessed by calling the inner function.
And when we call the inner function, we provide the second argument that is needed. The inner function can then combine the "magical" reference it has to the x value (provided when we made the parent call), with the normal argument it receives itself.
A simple way to look at this is as a function that returns a function--which can be called like a normal function because it is. So the first call of the function return type is a function.
Look the following example
function add(x,y){
return x+y;
}
function subtract(x,y) {
return x-y;
}
function calculator(type){
if(type ==='add'){
return add ; //here we are returning a function - the above add function
}
if (type==='subtract')
{
return subtract; // we are returning a function - the above subtract function
}
return null;
}
var fn = calculator('add'); // this call will return the function add which can be called as in below
var result = fn(4,5);
console.log(result) ; ///should print 9
Likewise the first call
var add5 = makeAdder(5);
returns a function which is exactly
function inner(y) { return x+5);
Then you can call add5(2) which essentially execute the above function.
I've just come across this little snippet of JavaScript code online:
exampleSocket.onopen = function(event) { // rest of code here;}
And I'm rather confused about the function(event) part, as there are no comments for me to analyze. (Who needs comments when you're designing bi-directional duplex connections? Haha ).
What exactly is function(event)? I always thought you had to define a function name with the function in javaScript. Is this an example of bad code? Additionally, the (argument-parameter-whatever) 'event' isn't even defined anywhere else in the code. Just bam. There it is. Is it necessary to define that, or is (event) a special predefined value? Lastly, if you were to replace (event) with some other value like (e), would the code still work?
Thanks
What you've got there is a function expression, not a function statement.
In a function statement, the name is mandatory. In a function expression it is optional. A function expression with a name is called a named function expression. A function expression without is called an anonymous function
There are a number of subtle differences between all these different methods of declaring a function which are covered in this question; var functionName = function() {} vs function functionName() {}
What you're doing here is setting the onopen property of exampleSocket to a function (expression). Note that you are not running that function at all; you are simply declaring it, and saving a reference to it in exampleSocket.onopen.
This means that someone can execute that function when they want to by calling;
exampleSocket.open();
They can pass a parameter to the function, which you can use inside the function using the event variable (and to answer your question; event is not a special word. You can call it anything).
exampleSocket.onopen = function (event) {
console.log(event); // will log "hello"
};
exampleSocket.open("hello");
The fact the variable event isn't used anywhere will likely mean the developer has named the argument to say "hey, look, you can use this if you want to", but hasn't in his actual implementation.
You don't have to declare the variable yourself. It is declared already by being named in the argument list, and it will be initialized to a value when someone passes an argument when they call the function.
Note that we could define this event handler using a function statement;
function foo(event) {
console.log(event);
}
exampleSocket.open = foo;
... or via a named function expression:
exampleSocket.open = function foo(event) {
console.log(event);
};
To confuse things (don't worry about this; it's a quirk of JavaScript) the name of a named function expression is only available inside the function itself;
exampleSocket.open = function foo(event) {
console.log(event);
console.log(typeof foo); // you'll get "function"
};
console.log(typeof foo); // you'll get "undefined"
... but in a function statement, you'll be able to access the name both inside and out.
I hope this helps... it's a bit of a "brain dump" of information :).
This is an anonymous function. A function is a value, and you can declare and store functions like this. More information on that syntax in this question.
Reading the code (I don't think it needs any more comments than it already has), you are writing a handler function which is called when the socket opens. The socket open event will be passed to the function in the variable event.
Why event? Because the API, whatever it is, expects to pass in an argument that represents the 'open' event.
It's a simple and common JS event-binding function.
It attach an anonymous function to the "open" event of "exampleSocket".
When such event is fired the declared function is called.
Each event may have some parameters, which contain additional info about the event itself.
You can name that parameter the way you want ("event","e" or "anythingElse") and then you can refer to it in the anonymous function body.
You are basically assigning a function value to exampleSocket.onopen, which can then be called elsewhere. Imagine something like this:
var obj = {};
obj.onsomething = function(a, b, c, d) {
alert(a+b+c+d);
};
obj.onsomething(1, 2, 3, 4);
In this case, I gave obj.onsomething a function that takes 4 parameters (should be numbers) and alerts the sum. Then I can just call obj.onsomething with 4 parameters.
So the function that you assign to exampleSocket.onopen will get called when it is appropriate (for example, when the socket is open).
Hope that helps.
1) I have an inner function that is event driven.
2) The inner function depends on variables in the outer function.
3) The variables in the outer functions are parameters to the outer function.
4) The outer function is being runned several times.
q) What values can I excepct the parameter variables from the outer function to have when the inner function gets triggered later on in the code?
scenario 1) When triggering the inner function, the exact state of the outer function that existed when creating the inner function is used.
scenario 2) When triggering the inner function, the latest value from the outer functions is used.
example:
function outerFunction(parameter) {
var object = new Object();
object.on('click', function () {
alert(parameter);
});
return object;
}
Each time outerFunction is called, a new event listener is registered for clicks on object. So, if you call:
outerFunction('foo');
outerFunction('bar');
you should see two alerts, one for 'foo', and one for 'bar'.
In case of jQuery (and, probably, similar libraries) each time you call on(evt, handler) you bind new handler to element for that event. And jQuery stacks handlers.
So if you do:
outerFunction(1);
outerFunction(2);
jQuery will bind two handlers, and when triggering 'click' on your object you will get, in sequence:
Alert for "1".
Alert for "2".
Fiddle for that: http://jsfiddle.net/ajWvk/
If it is your implementation of some abstract event-binding, and your implementation doesn't stack handlers, you will just bind new handler on each invocation of outerFunction, erasing all previous handlers.
In this case, calling:
outerFunction(1);
outerFunction(2);
will only alert "2", when "click" is triggered on object.
It depends on what parameter is. In javascript, strings and numbers are passed by value but objects are passed by reference. So if parameter is a string then it will work like bfavaretto said. However, if parameter is an object and you alert on parameter.text, then you will be alerted with whatever the current value of parameter.text is.
Try defining these in the console:
function outerFunction(parameter) {
setTimeout(function () {
console.log(parameter);
},5000);
}
function otherOuterFunction(parameter) {
setTimeout(function () {
console.log(parameter.text);
},5000);
}
Now, when you run this line it will log "test":
parameter = "text"; outerFunction(parameter); parameter = "hi";
But this will log "hi":
obj = {text: "text"}; otherOuterFunction(obj); obj.text = "hi";
I'm fairly new to Javascript and wrote the following jQuery code which works:
function updateItems() {
var now = Math.round((new Date()).getTime() / 1000);
$(".something").each(function() {
$(this).html(now.toString());
});
}
updateItems();
Why does this work? One might think that now would not be accessible from inside the function. I guess I could run some tests to see what happens if I try to modify now from inside the function, if I run another each() right after that, etc. But a basic understanding of how the scope works here and generally in Javascript cases like this would be greatly appreciated.
Also, is this type of function accurately called a "dynamic function" or is there a better name for it?
When you use function() { ... }, you create what is technically called a closure. They effectively can capture everything from the enclosing scope.
If you use now in the closure, you would get the value of now when you execute the closure, and (potentially) not the value it had when you created it.
Note that the enclosing scope here is the scope of the outer function, not of the outer block, and you may have to take extra care if you're creating closures in a loop, for instance.
This is just a nested function. It has access to the now variable because functions have access to the variables in scope where they're defined (this is actually how globals work as well). It's called a "closure" (it "closes over" the variables in scope where its defined), which sounds obscure, but don't worry — closures are not complicated (disclosure: my blog) once you know a couple of things about how JavaScript works.
The fun thing here is that it closes over the now variable that's specific to that particular call to updateItems, and the reference it has is live (it's not a copy of now as of when the function was created). Each call to updateItems creates a new anonymous function you're passing to each, and each of those functions has access to the now variable created during the call to updateItems. In your case, you're just using it immediately and returning, but what if you kept a reference to the function? What then? The answer is that's fine, it keeps a reference to the now variable it relates to:
function say(msg) {
var f = function() {
alert(msg);
};
return f; // We return a reference to the function
}
var s1 = say("Hi");
var s2 = say("there");
s1(); // Alerts "Hi" (see below)
s2(); // Alerts "there"
The call to s1 alerts "Hi" because the function created by our call to say still has access to the msg argument we gave to say, even though say has returned. And the same for s2, of course.
And just to prove that it's not a copy as of when the function is created:
function say(msg) {
// Create the function
var f = function() {
alert(msg);
};
// Update `msg`
msg += " (updated)";
// Return the function
return f;
}
var s1 = say("Hi");
var s2 = say("there");
s1(); // Alerts "Hi (updated)"
s2(); // Alerts "there (updated)"
See how the function used the updated version of msg, even though the function was created before we updated it. The function has access to the variable itself, not a copy of the variable's value.
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.