- [Instructor] Before we wrap up this chapter on functions and objects, I want to introduce you to the concept of closures. In the exercise files for this movie, 04_12, you find a function similar to what we've been working with before. We do some math here, set up three variables, and add one variable to the other, and return the sum. Now let's take a closer look at how exactly the browser would handle this code. When we run the script in the browser. It first discovers this function doSomeMath, but does nothing to it. Then it gets down here and finds the variable theResult, and sees that doSomeMath has been assigned to this variable.
That means it needs to run doSomeMath, so it jumps up to the function, sets up the three variables, performs the math, then places the result inside the sum variable, and returns the sum variable. The contents of the sum variable is then placed inside theResult, and the doSomeMath function is effectively closed down, and everything inside it is thrown away. The only thing we're left with inside theResult is the value nine, so that means if I go to my console, and I try to call for A, or B, or sum, I get nothing.
That's because they sit inside the scope of the function doSomeMath. We are now outside the scope, and these variables do not exist. So far, there's nothing new here. Now let's change this example a little bit. In the place of the variable sum, I'll create a new function inside the doSomeMath function. I'll call it multiply, and inside I'll set up a new variable result, and set result = a*b; and return result.
Then in the scope of the doSomeMath function, I'll return to function multiply. If I save this now, you'll see over here in the console, that the variable theResult, now holds the total function multiply with all of its contents. What's interesting is, if I run theResult down here in the console log as if it were a function, like we've done before, and Save, I get theResult of the multiplication a*b.
That's weird, and based on what we already know about how functions work, this shouldn't work. Why am I saying this? Well, think about this for a second. The browser reads from the top right? So it first finds the function doSomeMath, but does nothing to it. Then it jumps down to the variable Result, and sees that doSomeMath has been assigned to it, so it goes up to the top, and runs the entire function. It sets up the two variables, registers the multiply function, then goes down to the bottom and sees oh, I want to return to multiply function, but I don't want to run it, I'm just going to return it as if it was a variable, so I'll just place this multiply function inside theResult, and shut everything else down.
So technically, that means A and B should cease to exist, but if we look over in the console, it clearly doesn't, it's obviously still there. This here is what's known as a closure. What's happening is, this inside function multiply, relies on variables that have been defined in the outside function. And the browser is smart enough to understand oh, these things are related, so even though we've shut down the doSomeMath function, I'm going to keep these two variables alive, so that the multiply function can still use them.
If anyone ever asks you what a closure is, that is literally what it is, a function inside a function, that relies on variables in the outside function to work. So why do we have this feature? Well, it has some interesting practical applications. Let me show you a very simple example. I'll wipe out all my code, and then we'll start fresh. If you've ever worked with Ems in CSS, you know they can be a bit of a pain to calculate, especially if you know what the pixel value you're looking for is, and then you have to figure out what the similar Em value would be.
The trick with Ems is, if you know the pixel value of the current context, you can just take the pixel value you're looking for, let's say 32 pixels, and divide it by the current context pixel value, which, if you're just working in the browser as a whole, is typically 16. The result of the desired pixel value, 32 divided by the root pixel value 16, gives you the Em value. Using a closure, we can create a function that helps generate these numbers for us.
First I'll set up a new function, and I'll call it giveMeEms. This function has an argument, (pixels). This is the pixel value we want to convert into Ems. Inside the function, we have a variable called baseValue. I'll set that one to 16, because 16 is the base font size for most browsers. Then we set up an inside function called doTheMath. Inside doTheMath, we'll simply return pixels/baseValue.
See here we're grabbing that pixels argument, and using it inside the inside function, and then grabbing the variable base value, and also using it inside the inside function. And then finally to close things off, we return doTheMath. Now we can set up a series of variables calling for giveMeEms, and different pixel sizes, and get the values in return. So I'll set up var smallSize = giveMeEms.
And here I'll pass (12), so I'm looking for that Em value that would be equivalent to 12 pixels. Then var mediumSize = giveMeEms(18), var largeSize = giveMeEms(24). And finally var xlargeSize = giveMeEms(32).
Then to actually get the results here, I will console.log("Small size: " and smallSize). I'll just copy these. Medium, large, extra large.
And finally, I need to run the small size, medium size, large size, and extra large size variables as functions. And when I save this, and run it in the browser, I get the Em sizes for each of these sizes, 0.75, 1.125, 1.5, and 2. Again, this is only possible because of closures. In this case, the closure here contains both this variable base value, and the value of pixels, even though technically, the giveMeEms function has already run, and when we're calling it down here, we shouldn't be able to get these values.
- Working with data
- Using functions and objects
- Changing DOM elements
- Handling events
- Working with loops
- Making images responsive using markup
- Troubleshooting code
- Validating functionality