The course covers the following topics:
- Clarifying Terminologies (function vs methods, parameter vs arguments, and more!)
- Function Declarations
- Function Executions
- Default Parameter
- Rest Parameter
- Call Stack
- Arrow Function
- Nested Function
- Function Scope
- Callback Function
- Higher-Order Function
- Pure Function
Whether you're a budding developer, a student taking your first steps in coding, or even an experienced programmer looking to refresh your foundational knowledge, this course is created to meet your learning needs.
You can watch the full course on the freeCodeCamp.org YouTube channel (1.5 hour watch).
As one of the foundational pillars of programming, understanding functions is crucial for every aspiring developer.
This video will help you become an expert at functions.
Tapas has over 18 years of coding experience and has a passion for teaching and creating open source communities.
He's the teacher of this course.
So let's get started.
One thing I keep saying, folks, is that the concept is much, much bigger than the syntaxes while we'll be writing code, but we want to deep down in the concept first and then complete that with the syntaxes.
I hope you enjoy this entire course.
And if you so, please like and share this video.
If you have any doubts, comment below.
I'm going to respond to you with all the doubts, clarifications, be assured about that.
Okay, so a few things before we get started, how to take this course.
This is a longer video because of course, it's a crash course, we have to fit in a lot of stuff within one video.
But if you follow certain patterns, you will be enjoying the entire journey of going through each and every topic that we're discussing in this video.
Okay, so first thing, take breaks, don't try to consume all the content at once, take adequate breaks, and then try to feel like what you have learned are just few seconds back.
Second thing, after every logical chapter within this course, try to understand whether you have completely got the concept or not.
If not, go back and try to relearn.
No problem, any time go and try to relearn.
I will be teaching a lot of exercises.
So you have to do this exercise with me, but don't type them as I am teaching.
Okay, first, try to understand what I am teaching, try to completely get it in into yourself.
And after that, pause the video, try to do this, you know, those those quote, quote part by yourself.
All the code examples are already there on GitHub.
And the link to that is there in the comment section for the description section of this video, you can anytime pull it up and try to see like, you know, what is the code look like? So no worries about that.
But don't type the code as I am teaching, because then you won't be focusing on what I'm teaching, rather focus on learning, and then try the code out.
So go repeat, come back, learn and everything.
And in case there is nothing clear, feel free to comment.
I'm going to respond to you.
So without any further delay, let us get started.
Let's quickly talk about the concepts we'll be covering in this crash course.
Then we'll be clarifying few terminologies, there are a few terminologies, which are a bit confusing when you learn functions, for example, functions versus methods, parameters versus arguments, and there are many more such terminologies that we want to clarify.
Next we want to talk about function declarations, we'll be talking about function executions, then we'll get into call stack, we'll talk about arrow function nested function function scope, we'll talk about closure, we'll talk about callback functions, higher order functions, pure functions, we'll talk about IIFE, we'll talk about recursion.
So there are lots, lots, lots to learn, there are lots to talk about.
That's why I told you like when we go to each of this chapter in this course, try to understand one chapter before you go to the next one, and please practice the chapter before you go to the next one.
Alright, so take your time and let's get started with the learning.
It's the story of two friends.
One of the frame actually trying to cook a dish, but she doesn't know the recipe of how to cook it.
So she called her friend who is sitting abroad over phone, try to ask for the recipe.
The friend at the other end, she received a call and told the recipe line by line saying that, Hey, if you want to cook this dish, you have to follow this recipe like you have to put this first, then you have to put this one, then you have to cook it for so long.
And then finally, your dish is ready.
The friend cooked the dish following the recipe that she got.
But after a week, when she tried to cook it again, she felt like, okay, let me ring up my friend again and try to ask the recipe.
And the same thing happened.
The friend gave the recipe over phone.
She followed the instruction, cooked the favorite dish.
Next month, the story remains same.
She calls her the friend again, again got the recipe, cooked the dish for a few months.
It went on like that.
But after that, even though they are very best friend, the friend who is sitting abroad really got frustrated of it and just told, Hey, I have been telling you this recipe for like four or five months now.
Why don't you write it down somewhere so that you don't have to ask me again and again.
And I don't have to perform this task of telling you again and again.
Rather, wherever you're writing it, you probably can fetch it from there.
Then what the friend did, she wrote every instruction in a diary.
And next time onwards, she never rang up the friend abroad, rather followed it from the diary.
So it saves you from repeating the same task again and again.
Rather, you put the task somewhere, and then reuse that every time you have to perform the same.
Similarly, to that friend's story, who wanted to cook the dish, but finally, actually, instead of giving the task of her friend to tell it again and again repeatedly, she fetched it from the diary, the friend never had to perform the task again.
Okay, so with this analogy in mind, like reducing the task, performing the task again and again, rather, we will create something so that we can actually reuse it whenever required in our programming.
That's the very, very fundamental aspect of functions.
Now you'll be getting into a graphics through which the similar kind of story will be putting into the code in a visual way and try to understand what exactly function does programming.
The yellow box you see on the screen, consider that is a program.
And in that you have a bunch of lines of code.
Now, just look at it a little bit closely, there is a color coding, there are a bunch of black lines, then there is a green line, again, bunch of black lines, then is a red, orange, blue, again, bunch of black lines, and then there is a white line, right? So what I try to mean here, those black lines are the kind of code the same code has been repeated multiple times.
So three black lines, then some other code, then again, same three black lines have been repeated, then some other code, then again, same three black lines got repeated like that, right? So there is a repetition exist.
So what we do basically in this case, you know, going forward, is we first mark what are those lines that are getting repeated.
So you see here, we have marked those lines that are getting repeated.
And the next thing that we do is like, how can we make this code better, so that we don't repeat the same task, right, the same lines, rather than that, we kind of take those lines somewhere, give it a name, in this case, a name is like if you and fun.
And then what we do is like the same code that we got, change it in such a way that instead of those line, we are going to use the same entity, the one we had created before.
So do you see this one, the number of lines of code has reduced drastically.
So what we did, instead of repeating the same task in your code, the first one, we have now put the code in something which we call as function, given it a name call if you and fun, and then use that if you and fun in our code, instead of repeating those lines every time.
So we are not only reducing the number of lines of code in, you know, in our total source code, but what we are also doing is basically we are reusing something again and again.
Now think about the case, like why, why do we need it, the best case probably is, let's say there is a problem in these three lines, there is a bug in these three lines.
So in the previous case, if there is a bug, and you have to fix that bug, or you have to fix that issue, you have to fix this issue at least three times.
So you have to fix it in the first bunch of line, then again, the second bunch of lines, then again, the third bunch of lines.
But as we have put this thing into a function in a single place, and then reusing the same with its name in the multiple different places, if you have to fix the bug now, you have to fix it in one place, just inside that function's body just inside that function, and then rest of it will work.
So functions are a bunch of blocks that you keep together to perform something which otherwise will be very, very repeated in your code function should ideally have a name, but it can be without a name also, in most of the cases, you will have function with a name, so that you can call the function with that name.
So you me, every human being has a name.
And the purpose of the name is like, we will be called by that name.
And when someone will call us by that name will respond and say, Hey, I am here.
I am is the I am the person.
Similarly, for the function, when we call the function by the name, function will say like, Hey, I am here.
And inside this, I have this bunch of code, go ahead and execute this code.
I hope you understood it.
I know this graphics and please keep it in your brain.
Because, you know, the rest of the crash course, we are going to use this terminology again and again, you know, for better understanding in programming, at times, terminologies are much more harder than the programming itself.
And when a developer gets stuck on those terminologies, they feel so discouraged of learning that particular programming language, it happens.
So that's where we are learning any programming language or an aspect of an programming language, we have to make sure that we understand certain terminologies very well.
So some of the terminologies are functions and methods, what are the differences, we're going to talk about that, then declaration and definitions, what is the difference, is there a difference between them, arguments and parameters, we'll be talking about that as well.
And then callback and higher order functions, you will get confused often with these two, we'll be talking that also deep down when you go in the course itself.
So these terminologies, keep in your mind, like when we are talking about it, make sure that in your head, these terminologies and the differences or the similarities is completely chalked out, completely cleared.
If not, go back and try to see like where I have explained this one.
If you still have further questions, ask them in your comment section, I'll get back to you.
Let us now start creating functions and try to learn like how do we create functions.
Okay, I think before that, so you can use any editor like you can use Visual Studio Code or any other editor of your choice while coding.
What I'm using right now, I'm using browser's dev tools and the console tab, so that I can write the program here and execute them there and there.
If you want any other mechanism like you will be writing on Visual Studio Code and use the live server to run your program, most welcome, or you can actually practice them on the browser's dev tool.
Just go press F12, open the dev tools, go to console tab and start writing your program and execute it because you're just practicing at this point of time.
So first, first thing first, what we'll be doing now is we'll be creating function.
So we told that function is something which is going to help you to keep a bunch of instruction and code in a place so that you can reuse it again and again when you need it.
Now to declare or to define a function.
So our first terminology, bang, declaration versus definition.
So these two things are exactly same when it comes to function.
Function declaration, function definitions, defining a function is kind of same.
If somebody's saying I'm declaring a function or another person saying I'm defining a function, they are actually talking about the same thing, which is nothing but creating a function with bunch of logic.
So what we're going to do now, we're first going to create a function.
So to do that, I have to use a keyword call function.
This is the keyword, and then I have to give the function a name.
I told just now the function may or may not have a name, but most of the time the function will have a name so that we can call the function by its name, just like the human being has name.
There are situations where the function may not have a name and we'll talk about the situations in the in some time in this course.
OK, so let's first give a name.
Let's give a name called print me and then give a, you know, curly braces and then close that curly braces.
So this is what you have declared or you have defined a function.
OK, so right now the function has a keyword, a name, a bunch of parentheses, and then curly braces open a curly braces end.
Inside this curly braces, you are going to write every logic that you want this function to have so that you can reuse this logic anywhere you want.
For example, this particular function may just log certain thing into this console.
And on console, you have varieties of methods.
One of the method is log through which you can log something in the console so that you know you can actually read them or it's more for the debugging purpose that you can use.
OK, so let us do something like printing something like this.
OK, so I have created a function with a function keyword and the name called print me and the instruction the function has is is a log that I want to print in the console and that log says printing.
So this is my function definition or function declaration.
Now, as I have declared this function with a name, the next thing that I can do beautifully is by calling this function.
So to call this function, just type the name of the function, you know, print me over here, there is autocomplete already.
And then to call it, you have to give this parenthesis.
Otherwise, you are just printing this particular function's name.
And if you just do this, the function is going to print its complete body itself.
So if you just do print me the name itself, it is going to give you a string version of the entire function's definition or declaration that you have done just now.
But to execute to call it specifically, you have to give this parenthesis, you must give this parenthesis, and then you press enter, it will give its output.
It's just log printing, because that's exactly what we asked this particular function to do.
So our function has worked.
Now, as the function has worked, I want to just do something more with this.
OK, so this is where what I'm going to introduce something called parameter.
Okay, so let's write the same function function.
And we will say the name is print this.
And we will pass something over here, which we call as parameter, I'll get into it in a minute.
And then I'll close this function's body.
And inside this, what I'm going to do, I am going to write like console dot log, param.
So what is it? What does it mean? What what I have done here? Okay, so I have first, similarly created a function with the function keyword and the function name.
Here, I have not done anything between these two parentheses.
But in this case, I have done something in the parenthesis.
So whatever you put inside this parenthesis of a function, it's called parameters.
Okay, whatever you put inside this parenthesis is called parameters, you can put as many parameters that you wish to, as long as you need in your programming logic.
So if I am passing param is going to just, you know, I can use this param anywhere inside this function, so that I can do something with it.
So for example, I can just now do print this and pass this is going to print the thing that I have just given over here.
So it means I can pass a value to a function, and that value actually get mapped to the parameter.
And that's something that I can use, you know, inside the function to do anything that we want.
So again, there is a thing that I want to call out over here, there is a terminal logic thing, a parameter versus argument, anything in the function definition you pass inside this parenthesis is a parameter.
But when you call this function invoke this function, the actual value that you're passing to this function is called argument.
Okay, so that's the difference.
Sometime what happened that we call this also as parameter that I'm passing the parameter, we call this as an argument that I'm passing the argument, that's not the case.
So parameter is something that you pass to a function while declaring or defining the function, which is like this.
But when you call or invoke this function, the actual value you pass to it, it's called the arguments.
So I hope this is clear to you the parameter versus argument.
So we have defined the function.
And we have now know what is parameter we have now know what exactly is, you know, argument and things like that.
Okay, so the next thing, we have defined the function, but there is one more way we can actually declare or define the function.
That's called using the function expressions.
Okay, so what is expression, let's learn.
But before that, let me just clear it off all this thing that I have done, because I don't need it.
So if I say const count equals 200, this is an expression, what this expression has, it has a variable name called count.
It has like, you know, how we have defined this variable, we are saying this variable is a constant, and then is a value of this particular variable.
Okay, so const count equals 200 is an expression.
Similarly, we can actually define a function.
So let's take the print me function itself.
So in the print me function, the print me is nothing but the function name, which we can actually put as a variable over here.
And then what we can do here, instead of that 100 value, we can give function itself is a value.
And then we give the functions body.
And inside this function body, we can give whatever we need.
Sorry, it's got executed my bad, I'll just put it over here.
You can give console dot log, they print, right.
So this is what I am done.
So I have const print me equals to function and then this this thing.
So previously, what I have done previously, I have done this function, print me.
Okay, and then I have done here console dot log, say, printing.
So now, I have just defined the function, but I have defined the function in the function expression way.
So it means that the name that I have used for function before, now it's a variable basically.
And then the variable what I have assigned is nothing but a function, I have assigned that a function.
So it means print me is nothing but a function.
Now, when if I did const print me equals to 100, print me is nothing but a number, which value is 100.
Now I have done const print me equals to function, that means print me is a function.
And then I should be able to execute this function.
So first, I'll define this, okay, print me as already declared, because I have used this, let's use some other name for now, say print me again.
Okay, so this is the name, and then I do print me again.
And I have to execute me, so I have to do this parenthesis, and I got the print.
So this is another way I can actually define and declare a function, right.
Now, in the same thing in the print me again, let's say print me again, and let's say with param, what I can do now I can actually put any parameter here, right, or this time I'll put two parameters a and b.
And here after coming, I'll be actually doing a and b.
I have done now declared it.
Now let's say print me again with param, if I do 10 and 20 as an argument is going to print 10 10 10 and 20.
So I hope this is clear.
And now you know like how we can actually define a function or declare a function.
There are two ways we have done.
Okay, so one is with expression and that is without expression.
Let's learn how to return from a function.
So return is something you will be using very often when you work with functions.
So far what we have done, we have created a function, but inside that we have just done a console dot lock statement, which is not enough.
Usually what happened is like when you create a function, let's say function x, and you have something over here, right.
And then you will have say another function, y.
Okay, and you have something over here.
And then each of these functions are supposed to do their own task, right.
And in the entire program, our entire application is not like that you will have only one function, you will have multiple functions.
And what we'll be doing is like, if function x whatever is supposed to do, what you can use is basically you can use it like the output value of function x, and take this into a variable like say let p equals to this, and basically can use this p somewhere inside another function or anywhere else that in that matter.
So basically, whatever the value of that x function that returns, you can utilize that value anywhere else maybe in another function or anywhere in your programming, right.
So that is that is that is very much feasible thing in and the thing that you will be definitely doing.
Now this thing to happen, if you see this expression, let me remove everything over here.
And just to put this for your consumption, this particular expression, what we are doing, we are having a variable called p.
And the piece value is what is not the function, but the value we get from executing a function, because we told a function name along with a parenthesis means executing calling invoking a function of function name without a parenthesis means it just the string representation of the function definition itself.
This is a this is a difference that you have to keep in mind.
So in this case, we have parenthesis means the function will execute function will be called or function will be invoked.
And within that if the function is returning any value, if the function is returning any value, that value will be assigned to this variable.
What if the function doesn't return any value? What if it just has a console.log like we have seen the function so far, in that case, simply the function execution will return something very special, which is called undefined.
Okay, it means that something that is not defined yet is something called undefined.
Okay, so now let us create a function that returns something.
So for that, we'll create a function, say sum, and we'll do a summation addition of two things.
So we'll take a and b as two parameters, terminology matters.
And what we'll do is like we'll do return of a plus b, simple, which means that this is a function whose name is sum takes two parameters a and b, it sum up those two parameter with this arithmetic operation, and the result it returns, you know, back.
So let's execute sum, it takes two arguments.
Now, let's put two and three.
It means we are expecting a five is returning a five.
The same method, we can actually write a little bit differently how let's write the same method function, sum, we will do again a comma b.
And in this case, we just did return of a plus b, instead of that, sometime, you might want to do this also, like let return a variable a plus b, and then return that particular variable itself.
That is also same thing, same as you know, we have done whatever we have done before like returning a plus b directly, right.
So if it is just a simple calculation, returning it directly itself will be a shorter amount of code that people does.
So please follow that.
This is about returning returning from a function, it means everything that you do inside a function, all the tasks, all the logic, all the operations, and at the end of it, if you want the function to return a value, so that that value can be utilized elsewhere, you have to use a return statement, followed by what you want to return.
I hope this is clear.
What is default parameter? When you define a function, we know how to define a function.
So let's define a function function will take the same.
Okay, little bit different function, let's say calc is a function, and it takes a two parameters a and b.
And what we do, we will return some value and the value that we want to return is something like two into a plus b.
Okay, this is the value we are planning to return.
So what does this function do a simple function, a function whose name is calc, takes two parameters a and b, what it returns is for sum up these two parameters value, then multiply it with two, and then return something back a value back.
So let's execute this, let's call this function with two comma three.
Alright, so what it gives you, it gives you 10.
Yeah, of course, because two plus three is five, five into two is 10.
Similarly, you can do three into three, what is going to give you 12, three plus three is six into two is 12.
Now let's say someone in the team forgot to pass this second argument, what you get, you get not a number.
Why do you get an order number? Because when you don't pass an argument for a parameter for the function, the parameter value will be undefined.
We told about that.
So it means that in this case, you are not passing the second argument.
So value basically, so then b will be undefined.
Now a plus undefined on a will be three b is undefined, three plus undefined is not a number, of course, it returns not a number.
Now on a situation like this, instead of getting not a number, you might want to safeguard it with some kind of default value, right, some kind of default value of these parameters, so that at least this one fail like this, rather, you can safeguard them with some values of, you know, something that you are liking.
Okay, so what we're going to do the same function, I'm going to bring in again.
And now I can actually default it to zero.
Okay, it's a default value or default value for this parameter that I'm putting.
So it means if someone is not passing a value for this parameter using the argument, the value zero will be used instead.
Okay, so let's do this.
Now I'm going to do Calc three again, if you see this now instead of no n n, not a number, it is actually returning a value which is six, which is let's do the computation a is three b is zero three plus zero is three three into two is six.
Okay, so you can do a default parameter value for your function if it's required to.
And in that case, you can safeguard it from an unnatural value return value from the function like not a number.
And you can actually override the undefined value instead of having undefined, you can now set certain value with the default parameter.
What is rest parameter? The rest parameter is something that allows a function to accept any number of arguments as an array, any number of arguments.
Okay, now theory is one side, let's do it with example, let's create a function, let's say give a function name, we'll give a name call say collect things. Okay.
And we'll have two parameters of it first is x and then is y.
Now we are talking about rest parameters are different kind of special parameters, right, we know about default parameters.
Now, now we are learning about the rest parameters.
And I just now say the rest parameter allows a function to accept any number and infinite number of arguments as an array.
Now to make sure the rest parameter accept an infinite number of arguments, what we have to do, you have to give a special syntax to it, the syntax is with three dots.
So when we give three dots, what happened is like this, this, this particular parameter become rest parameter.
Now here are two things I want to call out a function definition can have only one rest parameter.
So it means that you cannot do x comma rest parameter y comma rest parameter z, you cannot do that.
So it can have only one rest parameter.
And the rest parameter must be the last parameter that you define for the function.
These two rules, please keep in mind, I'll repeat again, a function definition can only have one rest parameter as we have over here with y.
The rest parameter must be the last parameter like how we have here.
So you cannot have like you know, making this x as a rest parameter and then y as a normal parameter, you cannot have that rather you have to have like this, of course, the name suggests it means rest, rest means rest of it, rest of it means whatever is leftover.
So that is where it goes at the end.
Okay, now what I'm going to do, I'm going to do a console dot log of x.
And then I'll go do console dot log of y, so that I can actually print and see like what exactly it prints.
Now I have defined, let's just do collect things, sorry, let's just do collect things, and then pass some arguments, any number 5, 6, 7, 8, 9, okay, 9 enough.
Now what I'm going to do, I'm going to call collect things with nine arguments, I can pass 100, 1000s, millions if I have time.
Okay, so let's test it with 9.
So what will happen, the first argument that gets mapped to the first parameter, so x value will be 1, and the rest of it 2 to 9 goes to the rest parameter.
So it means y will now accept from 2 to 9, but within an array.
Okay, so if I just printing it, so if you see, the first sprints x is 1, and then rest of the 8 goes inside an array 2 to 9, this subscript is an array notation 2 to 9, and then that get assigned, this entire array get assigned to this y parameter, that's why it's called rest parameter.
Hope it was again easy for you to understand, and you will try to practice a lot about the rest parameter.
Let's learn about arrow function or fat arrow syntax.
Alright, so we know how to define a function, right? Let's do it again.
But this time, let's repeat the one we did with function expression, const add equals to a function.
And then we have two parameters over here.
And then we have return of x plus y.
And finally, we close this particular breast.
So that works, that's great, right? Now, what we can do over here to convert this one to a arrow function or fat arrow syntax that a few adjustment that you have to do.
So initially the arrow function or the fat arrow syntax looks little weird.
But how I tried to kind of remember writing it.
And right now, what happened is like, I hardly write a function in the regular definition or declaration way, it's always about writing the function with the fat arrow syntax or the arrow syntax.
Okay, so let's convert it, if you're new to it, you will take some time to get a grip on it.
But once you get a grip on it, I'm sure that you're going to write the arrow function again and again.
Because now I'm coming to the usage of it, because the best uses, you will write less number of code, you will write lesser amount of code.
And be it any framework or any library today in the modern web development, I think the de facto, the very normal coding syntax for function is using arrow function.
It doesn't mean that you cannot go with the traditional way of declaring and defining function or declare a different functions using expressions like the one we see on the screen, you can always go with that.
But if you use arrow function, or you use fat arrow syntax, it's like, you know, much more modern, is much more less code.
And of course, there is one more thing that is there which I won't be covering in this crash course in the but the but in the following one, the relationship with this keyword and arrow function, arrow functions, no binding to this keyword, that is what is another special case that comes but that will be covering into the this video that this keyword video that I'll be making next.
Okay, but let's now focus on how to convert this one to arrow function.
Okay, so to convert this one, what I have to do, simple thing, one is I'm going to remove this function keyword.
So you don't need function keyword at all to make an arrow function.
Next, we are talking about his arrow function.
So you need an arrow.
So arrow is a combination of this equals key, and this get it done.
So if you have a greater than and the equals and the greater than key without any space side by side, you actually have an arrow like syntax.
And this is what is making is an arrow function.
So this is an arrow function, okay, const add, this is the parameter that we are taking.
And then what is happening, basically, I am having an arrow and then the definition of the function.
That's all about the arrow function.
So I'm not using the function keyword at all.
So let's just make sure that it runs to comma three, it runs five.
Okay, very good.
But one more thing that I can do, if the arrow function body the arrow functions declaration, having only one statement, just one line and one and returning something, you don't have to even give this, you know, curly braces.
So this one you can very well define, like, you don't need this, just get rid of it.
And then you get rid of it, that's it.
So this syntax compared to this one, you know, the with the function keyword, this is much, much simpler, isn't it? So if you have a syntax like this, it is it is way, way easy for you.
And if it is something like, you know, you have dependency with just one parameter over here, you don't have to give this parenthesis, you can actually do things like this.
So if you have, you know, just one line stuff over here, so it's much, much simpler.
So this is the reason why arrow function is very well depreciated, very well appreciated by the developer community, it is very well received by developer community, because you will be writing very less syntax is very less code.
And in all the modern web development, you know, area that a function is used very heavily.
So please practice writing arrow function.
And I hope that you keep writing more and more arrow function in your code, then writing the function more traditional way.
All right, so nested function, what does nesting means? We know how to create a function, let's say we create a function called outer.
And that function has a body.
And it can have certain instruction, like what is this function supposed to do? Maybe in this case, a function is supposed to print something called outer into the log.
Okay, it might sound a little bit strange if you're new to it.
But this is a very, very powerful feature.
So if you want to understand closure deeply, I want your attention over here first understand what nested function is, how does it work? Up next we'll be talking about function scope.
And then we'll be talking about closure so that everything is very, very clear to you and is very straightforward to you.
All right, so nested function.
So function within a function, this means I can create another function over here, give it a name, maybe for simplicity, I'm giving it an inner.
And I can give a console.log.
As I've defined this function using the outer function, this function is called a nested function.
And this nested function as I've defined outside, you know, inside this outer function, I have to call this one inside the outer function itself.
Okay, so like this.
So right now, if I have defined it this way, and if I call the outer function, what will happen? The outer function will be invoked, it will print this console.log, then it will see this inner function has been defined, the definition happened.
And after that it will invoke the inner function also.
So what will be the output if I do this outer over here? Okay, so the output is outer and then the inner.
So it first print the log outer, and then the definition happened, the inner get executed, and this this inner actually gets printed out.
And it's a very powerful feature, we'll be able to see this in a moment.
Just now we have seen what nested function is.
And now we are stepping into understanding function scope.
Okay, these two are a bit interrelated, because you have to understand the concept of nested function, you can define a function within another function.
And then the function scope is important to understand who can access what Okay.
Now, there are certain generic rules.
But to understand those rules, I thought a graphical picture will be much more important.
So please pay attention to this graphic over here.
So the function is running globally, it means that the function is not inside any other function.
So this blue one is a function, this particular function is not inside any other function, okay, the function is just defined globally.
Now what happened, there are there are actually two rules, two primary rules that you have to keep in mind.
And these two rules are very important if you understand, I want to understand closure. Okay.
So the first rule over here is variable that are defined inside a function, the variable that are defined inside a function that cannot be accessed anywhere outside of the function.
Okay, so the variable that this one is defined inside this function cannot be accessed from anywhere outside of the function.
Okay, so anything defined in this blue box cannot be accessed outside of the blue box.
Understood first principle, okay, of variable defined inside a function cannot be accessed anywhere outside of the function.
Second principle, the opposite of it, a function can access all the variables inside the scope it is defined.
A function can access all the variable inside the scope it is defined.
So it means this blue function can access all the variables that is defined, you know, in the scope, the function is defined in the global scope.
So inside the global scope, if I am defining, I'm having any variable, I will be able to access that from this function, but the reverse is not true.
From the outside, you cannot access the thing which is inside.
Understood this rule, let's repeat this rule again because it's very important for us to understand closure.
Variables defined inside a function cannot be accessed anywhere outside of the function.
Second, a function can access all the variables inside the scope that it is defined.
So this blue box is defined in the global scope.
In the global scope, if there are any variables from this blue box, from the blue function, I should be able to access it.
Now we have learned about nested function, no? So just replace this global with a function and this function one with a nested function, okay, inner function.
So the global is outer function and this function is an inner function.
In this case also, then the formula remains same.
The rule applicable over here also.
So it means your outer function cannot access anything from the inner function as the inner function is defined in this outer function.
So it means the inner function will be able to access anything that is defined in this outer function because inner function is defined in the outer function scope.
Very simple, right? So now if it goes keep going nesting, like if there is another function inside, there is another function inside.
Same rule applicable.
We have the same rule applied over there.
So this is how it works.
So you have to keep this thing in your mind.
Now we are going to see with some code example here, okay.
We'll be seeing some code example over here.
But you have to really remember this rule that a variable defined inside a function cannot access anywhere outside of the function, you know, from outside of the function.
A function can access all the variables inside the scope that it is defined.
So these arrows and these things, if you keep it in your mind, I think things will be very clear.
Okay, so let's move on and try to see like how the things works code wise, we'll be doing some coding now.
So based on the rules that we have learned so far, we are going to write the code so that we understand this thing clearly, right? Let's create a function, let's create a function called a do something. Okay.
And what is this function doing? It's basically, let's create a few variables inside that.
So let's do let x equals to 10, const y equals to 20.
And then let const, okay, let's get var z equals to 30. Okay.
And then simply we'll do a console dot log of x comma y comma z. Okay.
So we know if I now do do something, I just call this function, I know what will be the output is 10 2030 very, very straightforward things that we have created over here. Okay.
So but this is where our rule number one comes into the picture, what was the rule number one variable defined inside a function cannot be accessed from outside. Right.
So it means I have defined let x const y var z inside the do something function and I've executed do something it executed this console dot log x y z.
Now if I try to take this console dot log and try to execute outside, what is going to happen? Do you see that? He says x is not defined.
Okay, x is not defined, maybe x is late, so it's not able to define.
Why also is cause not able how about a var? No, even if it is var, and it is defined within a function, you cannot access this variable outside a scope outside of this function, you cannot access that is the first principle that we have learned just now. Right.
Now, second principle, what was the second principle? Do you remember? The second principle was about if the function basically now can access anything and everything from its scope, basically the scope where it is defined.
Okay, so let's see the second rule.
Now what will be doing? We'll be defining var x equals to 10, const y equals to 20, let z equals to 30. Okay.
Now if I do function, do something and do a console dot log of x comma y comma z, what do you think will happen? If I just execute do something, what will happen? Do you think it is going to give an error or is going to print is going to print successfully? Why? Because our second rule say, wherever the function, whatever the scope the function is defined in that scope, if there are variables declared, the function can access this variable, this function is declared in the global scope, it means that function is not inside another function.
So it means if the global scope is having any variables, so the function will be able to access those variables inside the function itself.
But when we did the thing other way around, we have declared all this thing inside the function and tried to access them from outside, it doesn't work.
So these two rules define the functional scope, the scope that we are talking about is the functional scope, you have to remember what is accessible where simple thing if it is in the outer scope, if it is if it is defined in the same scope where the function is defined, it is accessible within the function.
But if it is defined within the function, it is not accessible from outside, even if it is a var that is declared and defined inside the function.
Clear about it.
There are higher chances that we'll hear back closures.
This is because the closures are not understood fundamentally by connecting the dots.
Okay, from connecting the dots point of view.
Now, coming back to closures, if you learn closures by connecting the dots, you will find closures understanding much easy, if you just jump into closure and trying to understand you may not understand it well.
But if you come from the background of nested function, then function scope, you will be able to understand closure very easily.
Okay, so let's get into understanding closures, so that we can actually feel it, it's easy.
Take a look into this picture on your screen.
So there is a box inside that there is another box, consider this one as an outer function, and this one as an inner function, we have learned about the nested function already, right? So let's give them a name.
For example, I'll give them give the for this one as f one as a function one, or we'll I'll give it as a name, the outer, to be very sure that they're out, this is outer, and this one, of course, inner.
Now, you know, if I define a variable over here, say a, this variable is not accessible from outside.
But if I define a variable over here, say b, this variable is accessible from inside the inner function.
So we have learned this in the nested function and the function scope very clearly. Okay.
Now, what is closure? The nested function is a closure, this inner function is nothing but a closure, okay, as simple as that.
So if anybody asked you a definition of closure, you can tell this nested function is a closure.
Now, if you go for a bookish, you know, closure and for example, if you go to MDN, and try to look for what is closure, you will get a definition like a closure is a function that can have free variables together with an environment that can run that variable, okay, which means it the environment is nothing but this inner function.
And the variable means every variable that is defined inside that inner function.
And there is an ability through which you will be able to run things which is in this inner function.
So this inner function is basically is a closure.
Okay, this is how we should be understanding closure.
Now, let me summarize.
The inner function can be accessed only from the statements in the outer function, correct, we'll see it in code also.
And the inner function from a closure, it means the inner function can use the variables, the arguments, everything from the outer function, while the outer function cannot use the arguments and the variable from the inner function here.
With this one, if we understand like what is closure, the closure is nothing but the nested function, because it provides an environment, you know, to the outer world.
So this nested function can leave in a longer, the nested function can leave longer for execution.
And it can actually perform the all the required operation.
Right, so let's write a function will give the team as outer.
And let's take a parameter of this one outer function.
And then let's take another function nested function, which is like inner, we will also take a parameter over here.
And what we can do here, this is the beauty of it, the inner function can access the outer functions variable and argument.
So I can do return x plus y, correct, inner function can access the outer functions argument or any variable that is declared inside outer function.
So I can do return x plus y pretty well over here. Okay.
And then finally, what I can do, I can do return inner.
Okay, I am returning this inner function as well. Okay.
Now since the inner function, the inner function is which one this one forms the closure, this is what is closure. Okay.
Now, what I can do basically, I can call this outer function.
Okay, and specify the argument, and then leverage both outer and inner together.
That's the advantage. Okay.
So let me see, how can I do this? I'll just press enter.
Now first, what I can do const outer return equals to outer, let's give 10.
What do you think will be returned over here? This is this is this is the most interesting part, what will return.
So once we call this outer function, outer function, return nothing but a function, which is like an inner function.
Now when the function execution is over, the call is over, that function is over, right? That function is nowhere in the picture.
So if I press and enter over here, outer is just over, it is nowhere in the picture.
But the beauty of it, the beauty of it is the argument I have passed to outer is still leaves, where is still leaves inside inner because this 10 was passed over here, this 10 is still used over here and this still leaves, even after the outer execution because outer returns the inner, the inner is actually over here outer return.
So let me just if I just do outer return for you, if I just do this one and print this for you, what it returns is returns inner y return x plus y, which is written this function, where x is nothing but this 10 that I have passed.
So though the execution of outer is over, but the value that we have passed through outer still leaves within inner.
So it means, it means if I just execute outer outer return now, oh, you to your outer return now, with a parameter set two is going to give me the output of 12.
Why? Because outer return is nothing but this inner function, inner function expects a parameter over here, the parameter that I have passed as the no pass the argument over here.
But what it did it actually use this two with a variable that I have passed long back and the execution is over.
That's why this is called closure.
This is created a closure closure is nothing but the variables and an environment that you can actually execute freely.
What do you mean by freely? It means usually in functions whenever the function execution is completely over, this is done any variable that is that is actually created inside that that's all gone is basically you are not going to get it anymore.
But in this case, though outer is executed long back, but the argument of the parameter we have passed through outer is still leaves within inner because inner is a closure, and I can actually utilize it, you know, at a later point of time.
So this is what the concept of closure that you need to understand.
This is what you need to understand is like, why closure is really handy method, why closure is really useful.
So you can use closure for various use cases.
One of the use cases that I have seen over here is like preserving the variable.
So I have passed 10 though the function execution is over, but still 10 is preserved over here.
And as it is preserved over here, it can be utilized with another value to compute something and return, right? That's why the closure is useful.
In the video that I'll be creating focusing on closure, only there I'll be talking about much more real life examples and the use case that you can actually build with closure.
So as you understand closure fundamentally right now, start practicing, start creating this kind of a small example where you have a outer function inner function, outer inner both takes some argument, you return the inner function from the outer function and see after outer execution gets over how the value that you pass through outer you can still used inside inner at a later point of time.
So this kind of thing, the example that you're seeing over here, try to find out this example over internet or try to cook something by yourself and try to practice it more use case oriented example like real life use case oriented example of closure that will come in a dedicated video.
I hope this clarify your concept.
Now just to recap it once the closure understanding is depending on your understanding of nested function plus function scope.
We know by nested function that a function can define one more function within it.
We know why the function scope is like the outer function cannot access any variable inside the inner function.
However, inner function can access any variable and the argument of the outer function.
This ability gives us a very powerful feature called closure through which even if the outer function execution is over, but we can persist certain values which was passed to the outer function within inner function and compute it at a later point of time.
I hope this is clear to you.
Now we learn about callback functions.
What is callback? Okay, so everything is in the name itself callback.
It means call it back some point of time.
But let's understand with some example.
What do you what do you mean by that? It means that we can create a function we have seen function definition we can assign a function we have seen like when you do const x equals to function and then basically we can assign this function to a variable.
We can assign a function we can return we can define a function within another function.
We have seen this from the nested function.
Now the next thing that we are going to see is like we can pass function as a parameter to another function.
Okay, that is where the callback function comes into picture and we'll see what is use cases are.
Okay, first, let's define a function called foo.
Okay, and this is the foo function.
What is this foo function doing over here? Let's assume that foo function can take another function as a parameter.
Let's pass another function function as a parameter called foo or let's call bar because that's foo bar bus are the things that we usually use these names for example.
Now as this function takes an argument which is nothing but another function.
So it means I can capture it as a bar parameter and assume that this bar is nothing but another function.
So it means that inside this I should be able to execute this function.
If it was a string I could have printed the string or concatenated with something else or done something with the screen.
If it is a number I would have done something with a number.
If it is a function I'll simply execute this function.
Now to execute this function we know that we have to give this parenthesis to call this function or execute this function.
This particular function is called a callback.
This particular function is called a callback.
But why? We'll come to that.
But first I want to execute this.
How do we execute this one? I have defined it.
Now if I have to execute this I know that foo takes a function.
So I can actually pass a function to it.
And let's do something like this.
So what I did? foo takes a function.
Of course we told foo takes a function.
The bar is a function.
And we execute it inside.
This means that I can pass a function as an argument to foo.
So I have passed a function.
Do you guys realize one thing over here? I have created a function which doesn't have a name.
So this function is called anonymous function.
The function that doesn't have a name is called anonymous function because it doesn't have a name.
And as I will be using this function instantly over here I didn't bother about creating it again.
So if I just execute this one.
This function get passed over here and then it gets executed in this line.
Once it get executed in this line this console.log get executed and it prints bar.
Same thing what I can do instead of doing this line for you to understand this better I can create a function with a name.
For example function named and instead of that I can actually say console.log of bar again.
Same thing like the previous function instead of passing it directly.
Now I can do foo of named. Right.
It's exactly the same thing that whatever instead of again declaring the function with a name function and then passing the function over here I just pass the function directly over there.
That's the only difference but output is same.
So now you know a function can take a function as an argument and I can actually do that.
And the function which is passed as a parameter and I am using it you know inside it at a later point of time is called callback function.
But why it's called callback function.
That's the thing.
Let's go from the beginning again to understand why it's called a callback function.
So again we'll be defining function foo take another function bar and let's say I have some condition.
Condition is if it's night consider that it's night is a boolean variable it can be true or false.
In that case you call bar.
Usually at the night only like you know bars will be like flourishing everywhere or let's say another condition is there if is drinks over check online in this case only ok.
Pelling mistake check online in this case itself you call bar.
So we have two conditions where we want to call this particular function call bar.
The one condition is if it is night then call bar function or maybe do an online call or network call to check whether the drinks is over then only you call bar.
So it means that calling back bar is based on certain kind of conditions that is happening within this function.
This is a case where you actually want to call this function as a callback function.
You are calling it back based on certain conditions based on certain things.
It is so so amazingly powerful because you can pass any function to another function and call this passed function based on any condition at a later point of time.
That's why it is called call back.
Now if you want to understand this concept with much deeper example.
I have created an example with the pizza hub or the pizza hub and a little boy story.
It's like a storytelling so that anybody can understand.
That video is already out there.
Go ahead and check out that video.
The link of that video is in the description of this video.
You can check out and find out like you know how in a real life application you can use call back you know effortlessly.
So I hope the callback functions is clear to you now.
Now we learn about higher order function higher order function or HOF.
What is higher order function.
A higher order function by definition is a regular function is a normal function that takes one or more function as an argument and or returns of function as a value of it.
Let's write it down.
It's a bit complex in that way.
So one condition is like it takes one or more functions as argument.
This is the first thing.
And then the second thing.
It may return a function.
So not necessarily both the conditions has to be made for a higher order function.
If any of the condition meets it's actually a higher order function.
Now we just now spoke about a callback function right.
What is told about callback function.
A callback function is a function which takes a function as an argument based on certain conditions or something.
Whatever the function we are passing as an argument it is going to invoke that function inside.
Now in the first case of the HOF higher order function is about taking one or more function as an argument.
So it means there is a relationship between a higher order function and a callback function.
And that is where sometime in interviews interviewers put some tricky question is HOF and callback are same.
No HOF and callback are not exactly same because for callback functions it is not mandatory for the main function to return any function.
It can accept the function as a argument.
Do something with it.
But it is not necessary that it has to return a function.
Whereas in higher order function if the function return another function it calls a higher order function.
In that case also it calls higher order function.
So it means that if I am just taking like a function.
Let's take a function.
Let's give it the name call gate capture and let's take a parameter called camera.
Now if I am doing like this.
This is a higher order function.
Why because camera is a function and I'm executing this one over here.
So I can actually call get capture over here.
I can call.
Sorry about that.
I can call get capture over here.
And pass a function to it.
I can say function.
Do a console console dot log.
Say can on.
So it execute.
This is what we have seen when we understood a callback function.
Now we can do the other part also like a function returning another function which is also called a higher order function.
So how it will be.
We can actually do like function return the f n and it can return a function with say a console dot log of returning something we are printing over here to prove that it works.
Now how am I going to execute this multiple ways to execute it.
Say f n equals to I can do return f n.
To return f n.
When I return f n what it does it return a function right now.
So if I do this.
So f n is now nothing but a function.
If you see that the moment I'm typing f n it is giving f.
If I just do a printout over here.
It is running a function to execute this one.
It means I need the parenthesis.
So it will execute this one.
So this is one way that I actually can execute this thing.
So I hope this is quite clear.
Now do you.
You know already.
And the higher order function is extremely extremely useful for you know your core reliability predictability aspects of it.
You are already using some of those things called array functions like map filter reduce find all this method that you have right on the arrays are all higher order functions because they are also you write a code like you know one if I take like one comma two comma three and on this array you do something like filter and in here you pass a function right your filter condition you pass over here if you are using array already you will know that and this is where you actually put your condition like based on which condition you want to filter this one out right you get this like element and if the element greater than two greater than three you know you actually write conditions like that and based on that you filter the things out.
So this is an example of a higher order function like how why exactly for higher order function and where you use the higher.
Now again if you want to get a very very deep look of higher order function as it is crash course we are not getting into too much deep but you want to get a very good deep of a higher order function.
I have already created a video for it.
Please take a look at it.
Please take a look.
Let's see what a pure function is.
By definition a pure function is a function that produces the same output for the same input.
So function say greeting input is name and what is going to do is going to return a greeting message.
So return hello and this kind of greeting message is going to return.
So if I call say greeting and pass my name is going to return hello tapas.
So for same input is going to return same output.
If I as many times I am going to input tapas that many times it is going to return hello tapas.
If I do hello YouTube it is going to return hello YouTube.
As many times I am going to input YouTube that many times it is going to output hello YouTube.
This is pure function.
Pure function helps in predictability.
It means that if the input is same output will be always same.
So this is very very predictable.
What is impure function? Just the opposite of that.
It means that for the same input it is not going to create the same output.
So same function if I just do a little bit different way.
So for example let me create a variable called greeting and what I did now initialized with hello.
Now I have a function like function you know this guy.
I will just copy this so that I can utilize it.
But I will change a little bit.
What I will be changing instead of this hello.
Now I am taking this greeting from here.
Alright so if I now say greeting tapas it will give hello tapas.
If I give tapas again it will give hello tapas.
But if I change this greeting variable value to from hello to hola.
Hello to hola.
And then I do it again for the same input tapas the output become hola tapas.
So from hello tapas it become hola tapas.
It means say greeting is not producing the same output for the same input. Right.
Because it is depending on something and that something is called side effect.
What is a side effect? The side effect is nothing but a variable which is outside of the scope of say greeting function and say greeting cannot control this particular variable.
Any anyone can change which can create a side effect such that this particular function is no more appear function.
It is no more returning the same output for the same input.
So this is the difference between pure versus impure function.
Can you write all the functions as pure function in your application may not be you may not be able to write you know all the functions as a pure functions because there will be side effects you need things like that you have to make network call you have to probably write something on the console log everything is side effect.
But as much as possible if you can make certain things as pure you have more more predictability for those cases.
So look out for this thing.
Again if you want to get deeper to pure function you want to learn like the real life use case of pure function where exactly we use where can we make use of it.
I have created an extensive video for pure function.
Take a look at it so that you can learn and practice it much more.
So I hope now you got the basic fundamental understanding of a pure and impure function.
All right friends.
So let's learn IFE.
What is IFE.
It's an abbreviation of the term immediately invoked function expressions I for immediately then I for invoked then if for function if or expression immediately invoked function expression what does it mean.
It means it's a function expression that's where the code inside the function gets executed immediately after it's been defined.
Now let's take a function for example function X is the function right which is having a name X.
Now if I have to execute this function at a later point of time whenever I want in my code what I'll do I'll just use this name with the parenthesis and execute this function.
OK that's great.
Now the only reason why this name exists the X for this function is because I can use this name to execute this function at a later point of time.
Maybe wherever I have defined this function after two hundred lines after that based on certain logic I am executing I'm calling I'm invoking this function.
But IFE says the use of IFE is to execute the function immediately after it's been defined.
So if I have to do that I don't need the name of the function because the moment I define right after defining the function I want to execute it.
So I don't need a name.
So let's start with something which doesn't have a name.
I did function X before I don't give any X now rather I have created something like this.
But if I try to run this it's going to give me a problem saying that function statement require a function name.
So now I cannot create an anonymous function like this and let's just keep it as it is because it's require a function name.
Now let me introduce an operator called group operator which is nothing but a bunch of parenthesis.
Now if I put this anonymous function the function without a name inside this group you know operator what happened if I just give an enter it actually gives me the string representation of this particular function itself.
The string representation of this function itself.
Without any name but string representation.
In previous chapters we have seen whenever we get a string representation of this function itself it means it's a function.
So it means I can actually give the parenthesis after that to execute it.
So it means if I take this guy and just put a parenthesis around this it means it will be executed.
So I have got a proper function that's got executed.
So this is what is IIFE.
So now let me write a few code inside this so that you know that it gets executed.
So console dot log IIFP.
If I just try to execute this you see that IIFE got printed.
So the function when I am defining at the same time I am also executing this function that is what is IIFE that is what is immediately invoke function expressions.
Now if you ask why does it exist there are a few reason why it exists.
Before ES6 I mean before we had like late const all this better way of managing accessibility of a variable like where it where what can be accessed where where things cannot get polluted where you have you know before ES6 where you had only var like the chance of your global variable gets polluted you had no other option that using IIFE to protect them.
Also another reason is like a very normal reason is like when you create a function with a function name it means the function name unless it is a like nested function or inner function the function name basically exists in the global context and the globally it is not inside any other function.
So it means there are chances that somebody else might be using the similar function name somewhere else might there is a chance of kind or a variable name with the same name as the function name and the chance of getting it polluted.
So for that not to happen the IIFE can be used.
So IIFE can be used for various different use cases but the concept of IIFE is this that whenever you actually define the function immediately after that you want to execute it.
Only in this case you use the syntax and use that IIFE.
I hope the syntax breakdown also makes sense to you because it doesn't need a name.
So we started with an anonymous function then we actually used a group operator around that so that we get a function definition and then the last parenthesis basically a pair of parenthesis used always to call or the invoke the function we use it along with it and we got an IIFE result then and there.
I hope it was useful.
Thanks for watching.
So we are going to understand call stack but before understanding call stack we have to understand function executions very well.
So first we'll understand what call stack is and also we'll understand what is function execution so that you get a complete clear picture about it.
The element that gets inside the stack first it comes out last. Right.
So here consider there are three elements like F1 F2 F3.
They went in like first F1 then F2 then F3 but when it had to come out the F3 come out first then F2 and then F1.
That's how the stack stack works.
Now instead of normal variable if a function gets inside a stack then it will be like similar way like first F1 F2 F3 gets in and then F3 F2 F1 it comes out in this sequence.
And in that stack it defines like how the execution of this particular function takes place.
The reason for doing this there is a proper sequence of how the functions are getting executed can be maintained through the stack data structure.
We are going to see that with example.
So the first example that we are going to take there are three functions F1 F2 F3 you are able to see on the screen.
Each of this function have bunch of code that can be executed whenever we are invoking or calling this function.
We are calling these functions first F1 first then F2 then F3.
Right side we have a function execution stack or call stack.
So call stack and function execution stack are the same.
What we're going to see like when these functions are getting executed like first F1 gets called what happened to call stack then F2 what happened to call stack then F3 what happens to call stack.
That's what we want to learn.
So please pay an attention to this call stack and also how the code is getting executed.
The first thing first F1 F1 gets executed F1 gets inside the call stack or the function execution stack inside F1 bunch of code.
OK all done done done getting executed.
There is no function inside it.
So nothing else to put at this point of time inside the stack.
Then F1 execution is over.
Take out F1 from it.
Next F2 gets executed.
Put F2 similarly over there.
There is no function inside it but execute all the code.
Execute F2 take it out.
Then goes to F3.
Again put F3 inside the stack.
Execution is done.
There is no function bunch of code.
Get it get it executed.
It's very simple F1 F2 F3 has got executed.
Now let's take a little bit complex scenario with this code.
So what is happening here you have F1 your bunch of code.
There is no function in it.
Then you have F2 a bunch of code but there is a function F1 which you have defined before we are invoking over here.
You remember a function can have another function inside it.
A function can invoke another function inside it.
This is an example.
So F2 basically invoke F1 or call F1 inside it along with a bunch of code.
F3 there is no other code other than it is executing F2.
It's like a chain. Right.
So any invoke F3 it is actually invoking F2.
F2 executing a bunch of code and invoking F1.
F1 executing a bunch of code but no function invocation inside F1.
Now how this can be depicted into call stack or the function execution stack.
That's what you're going to see.
So again pay attention to the right side.
First what happened when F3 executes.
When F3 executes it finds F2.
But before that F3 has to go inside the call stack because of function has to go inside call stack to get executed.
So now F3 get executed it finds F2.
F2 another function.
So before I take out F3 out of it because F3 will be taken out only when F3 is complete execution is over.
But it's not over now the cursor is at F2.
So it has to put F2 inside.
F2 came inside.
The F2's execution gets started but F3 is still in the call stack.
So F2's execution a bunch of code is executed this line get executed this line get executed.
Oh now it encountered F1 which is also a function.
It's time to put it in the call stack.
The F1 got into the call stack.
Now if you see in the call stack or the function execution stack you have F1 F2 F3.
But in the reverse order of how they have got entered right.
Now we are the F1.
F1 a bunch of line of code are there.
Let's execute them one by one.
But there is no function.
So nothing else to put into the call stack.
But execution when it is over for F1 we have to take it out from the call stack F1 is over.
Now our cursor is over here.
So F1's execution is over.
That means F2's execution is also now over take out F2.
So cursor is over here.
F2's execution is over.
The next line there is no more code.
That means F3 time to take it out.
Isn't that awesome.
So this is exactly what function execution stack or call stack.
That's how it works.
I hope it is very clear to you right now.
If you were interested go ahead and take that series.
I'm sure that you will be able to master that concept very very quickly.
Thank you for watching.
Let's talk about recursion.
What is recursion.
Recursion means a function that refer or call itself.
What does it mean.
Let's create a function.
Let's say function foo.
And inside that we create we do we OK function foo.
Inside that we do a console dot log.
Let's say foo.
And then we say that a recursion is something where the function can refer or call itself.
In this case we'll call itself.
What happened when we invoke this.
So we invoke foo.
Are you with me.
What is going to happen.
Do you see what happened.
The function is keep calling keep calling keep calling keep calling and after some point of time is going to say maximum call stack size exceeds.
So if you know about function call stack now it means that foo is going to put itself multiple times into the call stack call stack call stack multiple times and once will happen the call stack has a max size defined when the max size limit the threshold limit reached is going to give the error call maximum call stack call stack exceeds.
That's the error that we are getting.
But if you're getting an error what is the use of recursion.
We'll come to that.
Just a second.
But before that this is one way that we can actually define recursion like a function is actually invoking itself.
Let's do another way.
That's how the recursion can be done.
For example const foo equals to function bus and then inside this what I'm going to do I can call foo like this.
What will happen.
So in this case I have created a function and the function is assigned to a variable call foo.
So that means foo itself is a function.
So in this case foo and bus are almost same.
So whether you call foo here or you call bus here whatever it is you are actually creating a recursion here because now you are referring to this particular function either with foo or with bus whatever name it is it's the same function.
So that's the another way you create the recursion.
So in this case also it will just OK who is already exists because I use this name before.
So if you actually use it it is going to actually create the recursion for you.
Both the cases are same.
Now we saw like with recursion what was happening.
It was just creating it was calling itself calling itself calling itself and then it hits the maximum heap size and the error out.
Then why should we use recursion.
OK so one thing is like whenever you are using recursion you have to make sure that you have something called base condition.
This is very important.
So recursion without a base condition is not of much use base condition means under which condition you have to stop the recursion.
You have to stop the recursion at some point of time because you want to stop the execution of that function to execute itself at some point of time so that you can exit it out or do something else.
So that condition is called base condition.
So usually how you will be writing things in recursion in a recursion program.
So you'll write writing something like function recurse function recurse if it is a base condition if base condition in that case you probably do something and after that you return otherwise continue to recurse.
So this is how you actually do recursion.
You should have a base condition and if there is a base condition you do something and then return from it.
Otherwise you continue to recurse.
Let's write a program so that we can actually understand in a much better way.
So the program that we'll be writing is about let's say we'll be fetching water multiple times.
So let's call a function.
Create a function called fetch water and let's take a parameter called count like how many times you want to fetch the water and we say if the count is zero this is our base condition.
We have written the base condition.
In that case you do something.
Maybe I'll do like console dot log and say like no more water left.
And then I will return.
Otherwise keep fetching the water and I will do like count minus one and we can do a console dot log here also saying console dot log fetching water.
We'll see the enter code and then after fetching water we'll do that line got deleted somehow.
Fetch water count minus one.
So let's read this code once more.
What we are doing.
We have a fetch water.
We are calling fetch water again.
Here is a recursion of course but we have a base condition also.
The base condition is when we'll be exiting from the recursion.
Our base condition says when the count is zero then I'm saying no more water left and break this recursion but until count is zero I'm just recursing it just fetching the water.
So now if I say fetch water five times what will happen.
It will go count is five is equals to zero no it won't go inside that base condition doesn't meet.
Fetch the water become count four.
So count four means again call the same function with count four.
So count four comes here is four is equals to zero no again base condition doesn't meet.
Again fetch the water.
Now call the same fetch water with four minus one that is three.
Keep doing this until count is zero.
Once the count is zero no more water left and you exit from the recursion. Right.
So fetching water fetching water fetching water fetching water fetching water and then no water left.
So we have written a program using recursion and we also have the base condition through which we exit this recursion. Right.
Now the same thing you could have done with for loop isn't it.
The same function same functionality would you could have done with for loop.
So there is always some debate like whether you should be using recursion versus using for loop.
Wherever the for loop applicable maybe you should be using for loop.
But in some cases for example you want to create the factorial of a number factorial means factorial of n or factorial of five means five into four into two three into two into one. Right.
So the if you want to do a factorial maybe the recursion is the right way to go because it makes the code much more readable than doing a factorial using for loop. Right.
So readability is one of the factor that you want to probably take it into account when you use recursion over for loop wherever recursion is applicable.
So that's all about recursion.
Whenever somebody is asking about your recursion please also mention that you have a best condition where you can exit out from recursion.
I hope it was useful.
It's all right friends.
Everything has to come to an end.
So our this crash course also has to come to an end.
I hope you enjoyed learning all about the functions all the things about functions.
Some of them at a very high level.
Some of them in depth.
So we started with very basic things like how to create a function and ended with recursion in between we touch nested function function scope closure pure function call back all these various aspects.
But your learning should not stop here.
You need to keep practicing each of this concept much deep by with your hands on.
And I have videos for some of this concept to teach much more deeper way.
For example call back pure function HOF you know a lot of these things are having in-depth real life use case scenario videos.
Please go and watch them if you're interested or if you want to read it from somewhere or from some other YouTube channel.