More Closure Examples | JavaScript 🔥 | Lecture 129
Summary
TLDRThis video tutorial explores the concept of closures in JavaScript, offering two illustrative examples to help viewers recognize closures in their own code. The first example demonstrates how a closure enables a function to remember and access variables from its lexical scope, even after that scope has exited. The second example uses a timer to show that closures allow callback functions to access variables from the enclosing function's scope, even after it has executed. These examples clarify that closures form without needing to return a function from another function, showcasing their ability to maintain access to the birthplace variables, thus deepening the understanding of closures and their practical applications in coding.
Takeaways
- 🖥 Closures do not require returning a function from another function; they can occur in various situations.
- 📖 The example with variables 'f' and 'g' demonstrates that a closure can capture and remember the environment in which a function was created, allowing access to local variables even after their parent function has executed.
- 📈 Reassigning a function to a variable (like 'f' in the examples) shows how closures can update to encapsulate new environments, demonstrating the dynamic nature of closures.
- 🤖 Closures ensure that functions retain access to the variables of their originating scope, effectively 'remembering' the values at the time they were defined.
- 🚡 The analogy of a variable being inside the 'backpack' of a function helps illustrate how closures carry their scope with them.
- 🛠 Modifying the 'f' variable with different functions (as shown with functions 'g' and 'h') highlights how closures adapt to the current scope, changing the variables they enclose.
- 📚 The timer example with 'board passengers' function illustrates closures in asynchronous operations, where functions can access variables from their creation scope even if the parent function has completed.
- 💻 Closures have precedence over the scope chain, meaning a function will use variables from its closure before considering the global scope.
- 🏆 Identifying closures in your code is crucial for understanding behavior, especially in complex scenarios involving callbacks, timers, and asynchronous execution.
- 🔧 The script underscores the importance of closures in JavaScript, showing their versatility and critical role in function scope and execution context management.
Q & A
What is a closure in JavaScript?
-A closure in JavaScript is a feature where an inner function has access to the variables of its outer enclosing function, even after the outer function has executed.
Can closures be created without returning a function from another function?
-Yes, closures can be created without returning a function from another function, as demonstrated in the examples where functions manipulate external variables.
How was the closure demonstrated in the first example with the variable 'f'?
-In the first example, a closure was demonstrated by defining a function 'g' that assigns a new function to the variable 'f', which accesses and modifies an external variable 'a'. Calling 'f' later shows it retains access to 'a', demonstrating closure.
What happens to the closure when the variable 'f' is reassigned to a new function in the examples?
-When 'f' is reassigned to a new function, the closure changes to enclose the variables of the new assignment context, demonstrating that a closure always maintains a connection to the variables present at its 'birthplace'.
How does the second example involving a timer demonstrate a closure?
-The second example demonstrates a closure with a timer by showing that a callback function used in 'setTimeout' retains access to the variables of its enclosing function ('board passengers'), even after the enclosing function has executed.
Why does the callback function in the timer example still have access to 'n' and 'perGroup' variables?
-The callback function retains access to 'n' and 'perGroup' due to closure, which allows it to 'remember' and access variables from its enclosing function's scope, even after the function has executed.
What proves that closures have priority over the scope chain?
-The fact that the callback function in the timer example uses the 'perGroup' variable from its enclosing function's scope, instead of a global 'perGroup' variable, proves that closures have priority over the scope chain.
How is a closure's ability to 'remember' variables from its birthplace significant in JavaScript?
-A closure's ability to 'remember' variables from its birthplace is significant because it ensures that a function does not lose connection to its defining environment's variables, allowing for powerful programming patterns like encapsulation and factory functions.
What is the impact of reassigning a function to the variable 'f' on its closure?
-Reassigning a function to the variable 'f' updates its closure to enclose variables from the new assignment's context, illustrating how closures adapt to reflect the current scope of a function.
How does the concept of closures enhance the identification of them in code?
-Understanding closures helps in identifying them in code by recognizing patterns where functions access and manipulate variables from an outer scope, even after the outer function has executed, enabling more effective debugging and code optimization.
Outlines
🧩 Exploring Closures Through Examples
The segment introduces closures using two examples, emphasizing that closures can be created without returning a function from another function. The first example demonstrates how a function, assigned to a variable outside its scope, can retain access to a variable within its defining scope, even after that scope has ended. This is shown through the reassignment of the variable 'f' to a new function that still has access to the variable 'a' after the execution context of 'g' has finished. The second part of the example further explores closures by reassigning 'f' to another function within a different scope, demonstrating how 'f' can close over new variables ('b') from the new scope, showing the dynamic nature of closures.
🔍 Analyzing Closure Behavior in Depth
This paragraph delves deeper into the behavior of closures, particularly focusing on the transition of the closure from enclosing one variable to another as functions are reassigned. It highlights how closures ensure functions maintain access to the variables present at their creation, regardless of reassignments. The example used demonstrates that upon reassignment, the function 'f' changes its closure from enclosing variable 'a' to enclosing variable 'b', effectively losing access to 'a'. This transition illustrates the closure's ability to adapt to the function's current environment, ensuring it always remembers the variables of its 'birthplace.'
⏱ Demonstrating Closures with Timers
This section introduces a practical example of closures involving timers, illustrating how closures allow callback functions to access variables from their defining scope, even after that scope has ended. Using a 'board passengers' function that divides passengers into groups and sets a timer for boarding, the example shows that the callback function retains access to the 'n' (number of passengers) and 'perGroup' variables despite being executed after the 'board passengers' function has completed. This example underscores the closure's role in preserving the connection to its original variable environment, allowing access to variables defined in the parent function.
📘 Closing Thoughts on Closures
The final paragraph reflects on the preceding discussions about closures, aiming to enhance the viewer's ability to identify closures in their own or others' code. It positions closures as an essential concept in programming that will continue to appear in future coding challenges and discussions. The speaker encourages the viewers to think critically about closures, preparing them for an upcoming coding challenge that further explores this concept.
Mindmap
Keywords
💡Closures
💡Function Expression
💡Lexical Scope
💡Variable Reassignment
💡Global Scope
💡Execution Context
💡Callback Function
💡setTimeout
💡Scope Chain
💡Variable Environment
Highlights
We don't need to return a function from another function in order to create a closure.
A closure is created when a function closes over variables from its outer scope, even when those variables are not defined within the function itself.
A closure allows a function to access variables from its outer scope, even after that outer scope's execution has completed.
The closure contains the variables that were present at the function's 'birthplace' or the scope in which it was defined.
When a function is reassigned to a new value, its closure changes to include the variables from the new 'birthplace'.
A timer is a good example of a closure being created without returning a function from another function.
The setTimeout function takes a callback function as an argument, which is executed after a specified delay.
The callback function passed to setTimeout has access to variables from the scope in which it was created, even after that outer scope has finished executing.
The closure created by the callback function has priority over the scope chain, allowing it to access variables from its outer scope rather than global variables with the same name.
Identifying closures in your own code is an important skill to develop.
The examples demonstrate that closures can be created without returning a function from another function.
The first example shows how a function can close over variables from its outer scope, even when it is assigned to a variable outside that scope.
The second example illustrates how a closure allows a callback function to access variables from its outer scope, even after that outer scope has finished executing.
The closure created by the callback function includes the arguments passed to the outer function, as arguments are treated as local variables.
The coding challenge at the end of the video will provide an opportunity to practice identifying closures in code.
Transcripts
Let's now create two more situations
in which closures are gonna appear.
So that you can start identifying closures
in your own code in the future.
And both of these examples are gonna demonstrate
that we don't need to return if function
from another function in order to create a closure.
All right, so let's start with our first example here.
I'm gonna start by defining an empty variable called f
and then a function expression g.
So these are just some generic names
because what the functions do here don't really matter.
Then in here, I defined this a variable
and then I'm going to reassign the F variable
that we created out here.
And I'm gonna assign it a function value.
And this function will then simply log
the a variable to the console
let's say times two.
Okay, and that's it for now at least.
So let's try to call g
so that's gonna be dispersed function.
And so the result of this function is that a will be 23
and that F variable that we have out here
will become this function.
And so after g we can then call F.
So let's try that.
And we get 46 which is indeed 23 times two, all right.
And so what this proves is that this F value here
so this F function really does close over any variables
of the execution context in which it was defined.
And that is true even when the variable itself.
So F here was technically not even defined inside
of this variable environment here, right.
So this F variable was defined outside here
in the global scope, it was created here
but then as we assigned it a function here
in this the g function,
so right here at instill closed
over the variable environment of the g function.
And that includes this a variable.
And therefore it is able to access this a variable here
even after the g function here at this point
has of course already finished its execution, right.
So that's just what we learned in the last lecture.
So at this point of the execution,
the variable environment of g is no longer there, right.
But f, so this function here closed over
that variable environment and therefore it is able
to access the a variable.
So basically using the analogy of or less video,
the a variable is inside the backpack of the f function.
But now let's take it to the next level
and create a new function here.
So that's h and it's gonna be very similar.
All it's gonna do is to define b as some other value,
let's say this and then we will again,
reassign f, right here.
So let's call this one a b now of course.
So this one here will then try to access b
and multiply by two.
Okay, and so what I want to see with this
is what happens when we assign the f value
a second function.
Okay, so here we call g and so g will then assign to
or empty variable this f function.
Okay, and then if we call h afterwards
or actually let's do it after calling f for the first time.
So as we then call h then the f variable
will be assigned again.
So then a second function which is this one here.
And so what I want to see is what f does then.
So let's see.
And again, keeping in mind that F at this point
is a different function than this one here
because it was reassigned by h.
We just write that here.
Okay, and now we get 1554 which is probably 777 times two
and indeed it is.
And so this proves that the f function
it was reassigned here
also closed over the variable environment of h.
And so that's how it can access then the b variable here
which has set to 777.
So let's actually inspect the variable environment like
we did by the end of the last video.
So of f and then we will be able to see that in the closure,
it does indeed have the value of b
and it now no longer has the value of a.
So after the closure that it used to have before.
So at this point here at the closure contained
the value a and we can of course also see that.
So at this point in time, the closure is indeed a 23, right.
And so then as we reassign the function to a new value,
then that old closure basically disappears
and now the closure is b.
So this variable here of the birthplace
where it was reassigned.
And this is really fascinating in my opinion
that the closure can change like this
as the variable is reassigned.
So it really is true that a closure always makes sure
that a function does not lose the connection
to the variables that were present at its birthplace.
So it's always gonna remember them.
In our case here, the function
was kind of born inside of g first
and then it was essentially reborn again in h.
And so first the closure contained the a variable
of its first birthplace.
And then as it was reborn to follow our analogy
then it remembered this B variable off its birthplace.
Okay, so this was example one.
Let's now create another example.
Okay, so I hope the first one was clear here.
So whenever something like this happens
where your reassigned functions even without returning them,
keep in mind that also this will create a closure
but now moving on to our second example here
and that's gonna be a timer.
So a timer is another great example
that we don't need to return a function
to see a closure in action.
So here I'm going back to the example of the airline.
So creating a function called board passengers
and then we get the number of passengers and a wait time.
Then let's create a new variable in here
which I'm calling perGroup.
And that's because boarding usually happens in groups
and we usually have three groups.
So I'm gonna divide all the passengers.
So the number of passengers that is boarding by three
and by the end of this function,
I want to lock to the console.
We'll start boarding and then wait seconds, okay.
And now let's actually use a timer
and we haven't actually used a timer yet in this course.
And we will learn more about them later
but this is such a good use case
that I wanted to use a timer now.
And it's actually very simple.
So we just use the set time out function
and a set time out function needs two parameters.
The first one is a function which will be executed, okay.
And this function will be executed after a certain time.
For example, we can specify a 1,000 milliseconds
because the second argument here is milliseconds.
And so that will mean that whatever code
is inside of this function will be executed
after one second.
Let me actually do that out here
just so you see this as an example.
So if I saved us now wait one second
and then here you see timer appearing.
So I'm gonna do that again.
Okay, so you'll see that after this one second,
this function was executed.
Okay, and so this, as we already learned before
is essentially a callback function.
And in this case it is literally called later.
So in this case, after one second.
So let's create or callback function here.
And first I want to log to the console.
We are now boarding all and then the n passengers.
And so this n here is this parameter of the function.
So of this parent function which essentially is the function
or the scope in which this callback function here
is being created.
And so that will of course be important
for our closure example.
And then let's also use the perGroup variable now.
There are three groups each with
passengers, okay,
that's our function and now let's call it.
And here we want to specify wait and then times 1,000
because we're gonna pass into wait in seconds.
And this argument here needs to be in milliseconds
and so we just multiply by 1,000.
So board passengers, let's say we have 180 passengers
and it takes two, let's say three seconds.
So immediately when we call this function,
this variable will be created
then set time out will be called
and it will basically register this callback function here.
And then that will be called after three seconds.
But immediately also this console.log here
will be called, all right.
So this console.log here will not wait these three seconds
for these set time out callback to finish.
Okay, so immediately this variable is created,
this set timeout function is run and console.log is run.
And then after three seconds, this function here
will be executed.
And so let's see what happens to the n variable
and to the perGroup variable that is in this function.
So immediately we got this log and then after three seconds,
we are boarding all 180 and there are three groups
with 60 passengers each.
Okay, it worked.
And again, keep in mind that this callback function here
was executed completely independently
from the board passengers function.
All right, but still the callback function
was able to use all the variables that were
in the variable environment in which it was created.
So that's n and perGroup.
And one more time, this is a clear sign
of a closure being created, right.
So the only way in which this callback function here
can have access to the variables that are defined
in the board passengers function
that has long finished execution is if it created a closure.
And so that's exactly what happened.
And yeah, that's how we got access to perGroup
and also this argument of the function
so this wait here, right.
So as I mentioned in the last lecture,
the closure of course also includes the arguments
and that's because they are really just
a local variables in the function.
And to finish, let's now also prove
that the closure does in fact have priority
over the sculpt chain.
So here in the global scope,
I'm also gonna create a variable called perGroup equals
and then just some value here.
And so if the scope chain had priority over the closure,
then this callback function here
would indeed use this variable here
this global variable
because we can imagine this function here
basically being executed in the global scope, okay.
So if it wasn't for the closure it would use this.
So let me actually demonstrate that to you.
So if I remove this variable,
then it will be able to use the perGroup
and data is here outside.
So indeed now we get 1,000
but then as we put it back here
then the callback function will close over this variable.
So it will close over
the entire variable environment in fact.
And so therefore it will then use this year first, right.
And it did.
So in fact, a disclosure even has priority
over the sculpt chain.
Okay, and with this,
we finished these two lectures about closures
and they hope that after this one,
you are now a little bit better able to identify closures
as they happen in your code or even here in my code
throughout the codes
because we will see some closures happening
some more times in the future.
Now all there's left to do is the coding challenge
in the next video where you will be thinking
about closures one more time.
5.0 / 5 (0 votes)