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.
Related
I have the following code:
function doStuff() {
var increaseNumber = 0;
function doSomeStuff() {
console.log(++increaseNumber);
}
return doSomeStuff();
};
doStuff();
When function “doStuff” is executed, function “doSomeStuff”, which is inside function “doStuff”, gets triggered via “return doSomeStuff()” and increments variable “increaseNumber” by 1 each time it is called. If I change “return doSomeStuff();” to “return doSomeStuff;”, calling “doStuff” via “doStuff()” doesn’t work, as I’d assume.
Furthermore, I have the following code which yields the same result as the previous code:
var doStuff = (function () {
var increaseNumber = 0;
function doSomeStuff() {
console.log(++increaseNumber);
}
return doSomeStuff;
})();
doStuff();
In this code, an IIFE is stored inside variable “doStuff”. Inside the IIFE, function “doSomeStuff” is stored and apparently gets triggered via “return doSomeStuff” and increments variable “increaseNumber” by 1 each time it is called via “doStuff()”. When I change “return doSomeStuff;” to “return doSomeStuff();”, the code doesn’t work as laid out anymore.
When:
return doSomeStuff();
})();
//doStuff();
the IIFE and “doSomeStuff” are executed once and increaseNumber is = 1. Calling the IIFE further times via “doStuff()” doesn’t work, because of error: “JavaScript error: doStuff is not a function”.
There are mostly two things that I don’t understand here:
Why does the code work when “return doSomeStuff;”. I don’t see how this triggers function “doSomeStuff”, as the () is missing. When I call a function, I make sure to add (). That’s how I learned it.
ABOVE EVERYTHING: Why can I not call “doStuff” as a function when I change “return doSomeStuff;” to “return doSomeStuff();”?
You will notice that I’m still a Javascript novice rather. I hope I’m not repeating a question here (I honestly couldn’t find anything via search or on Google which would answer my query).
Thanks a million for any hints.
In this code, an IIFE is stored inside variable “doStuff”
No, the IIFE is run immediately, and its return value is stored in doStuff. So if you want doStuff to be a function that you can call multiple times, you need to return a function.
Why does the code work when “return doSomeStuff;”. I don’t see how this triggers function “doSomeStuff”, as the () is missing.
It's not going to trigger doSomeStuff, not on its own. The code inside the IIFE is just trying to create the function, not actually run it. The spot where you call the function is the () at the end of doStuff().
Why can I not call “doStuff” as a function when I change “return doSomeStuff;” to “return doSomeStuff();”?
Because in that case, your IIFE is returning a number, and then that number gets assigned to doStuff.
In Javascript functions are just like any other objects, we can return a function from another function, they can be passed as arguments to other functions etc.
When you return doSomeStuff; you are returning the function.
When you return doSomeStuff(); you are returning the value returned by invoking doSomeStuff function. It is same as
var result = doSomeStuff();
return result;
Now to answer the questions.
1. Why does the code work when “return doSomeStuff;”. I don’t see how this triggers function “doSomeStuff”, as the () is missing. When I call a function, I make sure to add (). That’s how I learned it.
As mentioned above you are returning the function here, Which gets stored to var doStuff. And it gets executed when you do doStuff()
2. ABOVE EVERYTHING: Why can I not call “doStuff” as a function when I change “return doSomeStuff;” to “return doSomeStuff();”?
If you change to return doSomeStuff(); you are not returning function anymore, instead you are returning the value returned by doSomeStuff function and gets stored to var doStuff. You can do () only on functions, since doStuff is not function you cant do doStuff()
In JavaScript return func(); returns the value which is returned by func(). On the other hand return func; returns a function, that itself returns the value returned by the function func. Both are two different things.
return func returns a function object. In javascript functions are treated as objects. return func will return the callable function object. Returning func() returns the value returned by the callable function.
Here is how it works.
Q1 (rephrased): "Why does this work?"
var doStuff = (function () {
var increaseNumber = 0;
function doSomeStuff() {
console.log(++increaseNumber);
}
return doSomeStuff;
})();
doStuff();
A1: Let's break it down to simple steps.
The variable doStuff is declared.
The IIFE runs, returning the function declaration doSomeStuff, which gets assigned to the variable doStuff.
Since the variable doStuff now holds a function, you can call it as you would call a normal function.
Please note, the once the IIFE has finished, the variable increaseNumber remains enclosed in its inner scope and is accessible to the function doSomeStuff. This inner scope doesn't get destroyed for the lifetime of doSomeStuff, which is now assigned to doStuff; This is why calling doStuff() leads to the desired effect, i.e. console.log outputs a number increment every time the function gets executed.
Q2 (rephrased): "Why can't I call doStuff as a function?"
var doStuff = (function () {
var increaseNumber = 0;
function doSomeStuff() {
console.log(++increaseNumber);
}
return doSomeStuff();
})();
doStuff();
A2: Again, let's break it down to better understand what happens under the hood.
The variable doStuff is declared.
When the IIFE runs, is calls the function doSomeStuff. Since doSomeStuff does not explicitly return anything, the JavaScript engine assumes it returns undefined. So doStuff now holds a value of undefined.
Since undefined is not a function and is therefore not callable, you will get a runtime error uncaught TypeError: doStuff is not a function.
Hope it helps.
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.
Crockford had this example to keep myArray from being in the global scope:
var myName = (function() {
var myArray = ['zero','one','two','three','four'];
return function(X) {
return myArray[X];
}
}()); // This function is invoked immediately
result = myName(3); // Now invoke it "for real"
Q: I don't get why it isn't
var myName = (function(X) {
Q: When I call myName(3), isn't "var myArray=" executed a 2nd time?
Suppose it's not executed a 2nd time because JavaScript knows that it's already been defined... What about a loop or some other logic between the var stmt and the return function stmt? Wouldn't it be executed every time?
Q: Can you name the subfunction and call it instead of calling myName?
okay, let's break this down...
var myName = (function(){
...
}());
that piece sets myName to whatever that anonymous function returns, so if it were:
var myName = (function(){ return 42; }());
myName would equal 42. If that doesn't make sense, this is the same thing:
function someFunction(){ return 42; }
var myName = someFunction();
So in your example, myName is set to function(X){ return myArray[X] }. So myName is a function. When you call it, the only code that is run is return myArray[x]. myArray is kept in what is called a closure, it is only exposed to the myName function and the anonymous one surrounding it.
I wrote an article on closures years back that may help you: http://www.htmlgoodies.com/primers/jsp/article.php/3606701/Javascript-Basics-Part-9.htm (scroll down to the "Closures" header).
OK here it goes ..
answer to Q1 . it is not myName = (function(x) because the part inside the brackets returns a function which takes X . i.e. myname is not assigned to (function(){}) but to the return value of it .
Q2. No when u calll myName 2nd time it already points to the inner function hence the outer function is not invoked at all .(this is the sepciality of closures where the value stays alive in inner function even if outer functions are completed.)
Q3. Well nopes we can name the inner function but the name will be valid only inside the outer function and since outer function has completed the name would be useless.
The outer function doesn't have to have an argument X, because it's only purpose is to return another function (which then is parametrized). Thus no argument is needed here.
Thus the only effect is to bind the function(X)... thing to the variable myName. Therefore no other constructs like loops or so does make sense here.
Q1+2: Note the () right of the comment "This function is invoked immediately". The outer function defined is not stored in myName, but immediatly called. Itself then returns an anonymous function which has no name and requires a single parameter (X). This function beeing returned is stored in myName.
To grasp closure you should start thinking about functions just as another value of a variable which can be stored and returned jsut as any other value.
Q3: myName is the subfunction.
Okay answer in turn:
First, why it's var myName = (function() { and not var myName = (function(x) {
In this case because the x value isn't required to create the function you are returning. The data structure of the array contained in the returned function is hard coded and so you don't need additional information to construct it. Much in the same way that
function a() {
return 1 + 2;
}
Doesn't have any arguments, because it's values are hardcoded. This is an example of functions as data or first class functions
Question two: is var myArray executed every time.
The short of it is no. myArray has been assigned to at this point so it has a value that the system has already calculated. In this case it's a function. The myArray potion has been set and so there is no cause to keep executing it. If the outer function didn't return a new function then yes it would need to get called again and again but that would defeat the purpose of this abstraction.
Question three: can you call the inner function.
No, it's out of scope. The entire point of this example is that you have defined a function generator.
Answer to first question:
no, the first "line" is returning a function so when you call "myName" you are actually executing the returned function
function(X) {
return myArray[X];
}
Answer to second question
no, such a function can still refer to the array "myArray"... in fact the purpose of this closure is to make myArray available in the global scope
In words:
myName is the result of an immediately executed anonymous function. It returns a function reference (to an anonymous function). That function has one parameter: X. After execution of the topmost anonymous function, myName is a reference to the inner anonymous function.
Now the inner anonymous function has access to myArray via a closure (myArray and the returned anonymous function both live within the scope of the topmost anonymous function). So if you execute myName, you actually execute the inner anonymous function, which can access myArray.
The topmost anonymous function is executed immediately and once (it returns a reference to the inner function). So myArray is declared within that execution context, and only once.
Since the definition of the myName object (function) ends in '()', its function is called immediately, returning a new function which has the myArray variable statically bound to it. myName is then accessible globally but myArray is not as it is within a function closure. When you reference myName() it has exclusive access to the bound array.
This approach ensures that myArray is only allocated once, when the outer function 'is invoked immediately'. After it is invoked, myArray isn't in the global scope, but is still available to the anonymous inner function.
The approach you proposed would work, but would require that the array be allocated each time the function was called. (Or be allocated outside the function, in the global scope.)
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.
Now, I usually call a function (that requires no arguments) with () like this:
myFunction(); //there's empty parens
Except in jQuery calls where I can get away with:
$('#foo').bind('click', myFunction); //no parens
Fine. But recently I saw this comment here on SO:
"Consider using setTimeout(monitor, 100); instead of setTimeout('monitor()', 100);. Eval is evil :)"
Yikes! Are we really eval()-ing a string here? I guess I don't really understand the significance and implications of 'calling' a function. What are the real rules about calling and referring to functions?
In JavaScript functions are first-class objects. That means you can pass functions around as parameters to a function, or treat them as variables in general.
Let's say we are talking about a function hello,
function hello() {
alert('yo');
}
When we simply write
hello
we are referring to the function which doesn't execute it's contents. But when we add the parens () after the function name,
hello()
then we are actually calling the function which will alert "yo" on the screen.
The bind method in jQuery accepts the type of event (string) and a function as its arguments. In your example, you are passing the type - "click" and the actual function as an argument.
Have you seen Inception? Consider this contrived example which might make things clearer. Since functions are first-class objects in JavaScript, we can pass and return a function from within a function. So let's create a function that returns a function when invoked, and the returned function also returns another function when invoked.
function reality() {
return function() {
return function() {
alert('in a Limbo');
}
};
}
Here reality is a function, reality() is a function, and reality()() is a function as well. However reality()()() is not a function, but simply undefined as we are not returning a function (we aren't returning anything) from the innermost function.
So for the reality function example, you could have passed any of the following to jQuery's bind.
$('#foo').bind('click', reality);
$('#foo').bind('click', reality());
$('#foo').bind('click', reality()());
Your jQuery bind example is similar to setTimeout(monitor, 100);, you are passing a reference of a function object as an argument.
Passing a string to the setTimeout/setInterval methods should be avoided for the same reasons you should avoid eval and the Function constructor when it is unnecessary.
The code passed as a string will be evaluated and run in the global execution context, which can give you "scope issues", consider the following example:
// a global function
var f = function () {
alert('global');
};
(function () {
// a local function
var f = function() {
alert('local');
};
setTimeout('f()', 100); // will alert "global"
setTimeout(f, 100); // will alert "local"
})();
The first setTimeout call in the above example, will execute the global f function, because the evaluated code has no access to the local lexical scope of the anonymous function.
If you pass the reference of a function object to the setTimeout method -like in the second setTimeout call- the exact same function you refer in the current scope will be executed.
You are not doing the same thing in your jQuery example as in the second setTimeout example - in your code you are passing the function and binding the click event.
In the first setTimout example, the monitor function is passed in and can be invoked directly, in the second, the sting monitor() is passed in and needs to be evaled.
When passing a function around, you use the function name. When invoking it, you need to use the ().
Eval will invoke what is passed in, so a () is required for a successful function invocation.
First of all, "()" is not part of the function name.
It is syntax used to make function calls.
First, you bind a function to an identifier name by either using a function declaration:
function x() {
return "blah";
}
... or by using a function expression:
var x = function() {
return "blah";
};
Now, whenever you want to run this function, you use the parens:
x();
The setTimeout function accepts both and identifier to a function, or a string as the first argument...
setTimeout(x, 1000);
setTimeout("x()", 1000);
If you supply an identifier, then it will get called as a function.
If you supply an string, than it will be evaluated (executed).
The first method (supplying an identifier) is preferred ...