What do you want to learn?
Skip to main content
by Jason Millhouse
Start CourseBookmarkAdd to Channel
Table of contents
Forest of Function Expressions
Function Expressions and Anonymous Functions
Function Expressions as Direct Parameters
Welcome back, in this section, we'll be looking at how to use function expressions with the map method of arrays. A function expression is just that, an expression, and you can use it in any place that an expression might go. You don't necessarily need to store a function expression inside of a variable at all times. Let's take a look at why. Say we had an array of numbers and we stored it in a variable called, as you might expect, numbers. And then we established a new variable called results. To that variable, we will assign something very special. You can see that we call the numbers array with its map method and then inside the parameters for that map method, we're going to pass some coolFunction. Be aware that the map method of an array will always take in a function as a parameter whether it's a function expression or a function expression stored in a variable, but it just has to be a function that the map method gets. Check this out. Here is the visual impression of our numbers array with each of the numbers inside of its own cell, and what the map method does, is it takes our coolFunction and applies it to every single cell. Whatever coolFunction does, it does it to each one of the cells in turn. You can see that our coolFunction here, whatever it may do, it gives us words in our final array that says, wow these are some pretty cool results! Now you might be thinking, this seems kind of like a loop format, and guess what, it sort of is. Here's what this sort of functionality would look like in a loop format. Well the first thing we would do is establish a results variable and then use a loop to go over each item inside the numbers array and then we would use our coolFunction on each item inside of the numbers array, storing the result in the results array. What's cool about the map method is that it takes all that code you see there in the loop and does it all conveniently in one line of code. Now let's actually build a function to pass to our map method. This time we won't use a variable, we will use a built function expression in the parameter parentheses. Let's check that out. What we're going to do is we're going to just simply double each number inside of our numbers array. There's our function keyword, and here we have, right after the function keyword, our parameters with the arrayCell parameter. That's because we have to pass each cell of numbers into our function expression in order for the function expression to know which one that it is looking at. Inside our function body, we'll say just return the array cell, whatever that may be, times two, so we will get a doubled value. That will be passed into the identical cell of the results array. Something important here to remember is that you always have to close your function body, so make sure that you put a bracket at the end of your function body, as well as close the map method with a parentheses. Then, tying the whole statement together, since we do have an assignment here, is a semicolon to make sure that we execute the function and pass all of the results to the results variable. Let's check out how our doubling function works. We pass it right into the map method and it is applied to every single cell of the numbers array and you can see each one of these numbers being doubled in turn. Then, if we were to log out our new results array, we would see an array with all of the values doubled from our original numbers array. Oh hey, one more thing, short functions are often built in one line for clarity and simplicity. You don't always have to build full blocked functions inside of a parameter. If it's nice and short, sometimes for clarity, simplicity, legibility, we will build those functions all in one line.
Returned Functions and Immediate Invocation
Cold Closures Cove
Tracing, Building, and Using Closures
Modifying Bound Values After Closure
All right, so now in this section we're going to look at a very important feature of closures specifically their ability to modify their bound variables in the background. Let's take a look at that. So, to demonstrate that specific behavior, we're going to add a passenger tracker to our buildCoveTicketMaker. What's a passenger tracker? It will keep track of how many times we've given a specific ticket to any particular mode of transportation. So, here's our original function and we'll shuffle it up a little bit and we're going to stick a new variable here at the very beginning of that function called passengerNumber and we're going to set it equal to zero. What does that mean? That means that every time we build a ticker maker it will get a passenger number of zero to start. We're still going to return the function that has our alert in it but inside that function we will increment our passengerNumber. And what does that mean? Well, it means that when a particular ticket maker is called whether for the submarine or for the battleship we know that a new passenger has been added, so we will increase the amount of tickets that have been given. We'll also add to the alert printing out the passengerNumber. Now when we call our buildCoveTicketMaker for our submarine well, we'll get a ticket maker back and inside that new ticket maker when we call it we see our new passengerNumber incrementer as well as our new line inside of our alert. Something you should notice is that passengerNumber's initial value is not evident here but it does start at zero and gets incremented every single time our ticket maker is called. So, let's scoot aside our semicolon here and put Mario trying to get a submarine ticket again and what happens? We get a ticket that says here's your transportation ticket via the submarine. Welcome Mario, you are passenger number one. That's because this is our very first call to getSubmarine Ticket and our passengerNumber has been incremented to one. Now what would happen if we then put Toad asking for a submarine ticket? He wants to ride with Mario. So, look, we get you are passenger number two. Wow, so that's pretty cool, right? That means that even though our function's locals group has completely disappeared, it has retained the value every single time of our incremented variable.
Dangers at the Moment of Closure
So, now that we've had a chance to melt your brain with some closures, we want to show you some common mistakes that happen with closures and then maybe give you some preventative measures to make sure that you don't make those same mistakes. The most common mistakes with closures occur inside loops. So, what we're going to do is we're going to try to make a torpedo assigner for our cove's submarine. Let's take a look at that. We'll work with a function called assignTorpedo. That means we're going to try to give a specific passenger on the submarine a torpedo to be in charge of. We'll pass in the name of a passenger as well as a list of those passengers. We'll establish a torpedoAssignment variable. That's going to eventually hold our torpedoAssignment function and now we'll build a loop that checks the entire passengerArray for the specific passenger that we want to assign a torpedo to. So, when we find the passenger, we will start to build a function and inside that function we'll alert ahoy to whoever the passenger is, man your post at Torpedo Number and then we will use their index value adjusted for zero to assign them to the right torpedo number. Then of course at the very end we'll return our torpedoAssignment variable that holds our function expression. Now we'll establish an array called subPassengers and we'll put a whole bunch of passengers in there that you may recognize. Next, we'll make a new variable for a new function called giveAssignment and then we will call our assignTorpedo function, we'll pass in Chewie as the passenger we want to assign the torpedo to as well as the list of all of the subPassengers. Then when we call our giveAssignment function we should expect that oh no, what happened? Ahoy, Chewie, man your post at torpedo nine? That's no good. Chewie's not an index nine. What happened? It should be torpedo four. So, the mistake that we made here is not knowing that closures bind values at their very last opportunity. It's really important that we pay attention to when we return our functions and the final variable states that happen when we do the return. So, way before torpedoAssignment ever gets returns the I loop counter has progressed in value all the way to eight and stopped the loop. What happens then is that eight plus one happens to be nine when the torpedoAssignment variable is returned. The function's actual return is really when the closure occurs. That's when the environment is packaged up together with all of the necessary variables and returned. So, when we called our torpedo assigner for Chewie the I value that was actually in the function was eight and so, he got torpedo nine. But what can we do to sort of ensure the correct value every time? There are several options that we could use. Let's take a look. First of all if we get rid of the torpedoAssignment variable entirely and just have a function expression, then if we scoot our function keyword over and automatically and instantly return as soon as we find our passenger, then we will have locked I into place and when we call our function, we find out that Chewie is assigned to exactly the right torpedo and that's because I, the I value, our loop counter was not allowed to progress. A second way that we could ensure the correct value is to design our torpedo assigners just like we did our ticket makers for the modes of transport. Let's take a look at that. So, we'll change our function's name to makeTorpedoAssigner but this time we will only pass in the passengerArray, not the name and passengerArray because the name variable we're going to pass into our function expression. Inside our function expression, we'll have our loop. Notice now that the loop is inside the function expression. Something to note here as well is that passengerArray is actually being closed into our function expression. Notice that passengerArray is a parameter and not a variable we ever established inside of our function. That's because parameters can be closed up too. So, inside our loop we'll of course check to make sure that we found the right name and when we do we'll alert our message. Again, the only closed variable that ever comes from the external scope is passengerArray and that never changes. Whoa, we love that. And now we can pass torpedoes out like they are candy. TIE fighter dead ahead. But we're sort of underwater with the submarine. Anyway. So, when we finally make our torpedoAssigner and then we pass Chewie to our getTorpoedoFor variable we'll get the Chewie has torpedo four just like we wanted. Additionally, we could call it again but this time for R2-D2 and we should get that torpedo six belongs to R2-D2 and we do.
Analysis of Load Order and Build Planning
Ocean of Objects
Object Creation and Manipulation
Functionality in Objects
(music) Welcome back. In this section, we will be exploring functionality inside of objects. So here, we're going to start with an aquarium object. We are in the ocean of objects after all. An aquarium object filled with other objects. And let's first build some add and remove functionality for our aquarium. Inside our aquarium, you can see we have some fish, a starfish, as well as a couple toys, a Coral Castle and a Dragon Statue. Our aquarium looks pretty good, but what if we wanted to add some creatures? Well we can build a function called addCritter, and in that, we would pass a container. In this case, we're probably going to be passing the aquarium, as well as the name of our creature, the type, the species, and the length. We could also create an addToy function. This one would get the container, the name, the type, the material, as well as whether it moves or not. To add a creature to our container, we would do container a brand new object literal, where we pass the parameters in to each of the properties for that object. Now wouldn't it be nice if these functions actually belonged to the aquarium instead of being external to the aquarium itself? Let's try adding one of these functions to our aquarium object. Important thing about objects is that properties can also be functions. That's going to allow us to add our addCritter function in. Something to be aware of is that you will often hear an object's function properties being referred to as its methods. So to add a new property that holds a function, we would just create an addCritter property much like we would create other properties, and then inside of it, we would build an anonymous function. Now something to really pay attention to here is that our container parameter has disappeared. And that's because we're making the function belong to that very container. We're going to use some special syntax now that refers to the aquarium object. Now the this keyword will always refer to the owner object of the function in which the this is used. So in this case, when called, addCritter will say, hey aquarium, that's what the this does. Make a new property with this name, that's the one in the bracket, and then assign to it an object with these particular properties. Sweet, we've got a property that holds a function, awesome. And now it's available as a property on the aquarium object, so let's go ahead and add a creature. Lets add a yellow tang called Bubbles. If we pass in the name Bubbles, which we know is a fish, and the kind of fish is a yellow tang species, and its length is 5.6. We just call the function, just like referencing any other property in aquarium, but in this one, we put up a set of parentheses for parameters and pass in the information. And here comes Bubbles, drops into the aquarium, and we have all of Bubbles' properties set correctly. Well, our tank's looking a little full so let's try to build another method that will be able to remove any of the objects from our aquarium. And since you already know how to build a function inside the object literal with a property, let's now try to build a function on the fly, and we can do that with the dot operator and a function expression. All we will need here to delete any property, whether it's a fish or a toy or even a function, is its name. What we'll need here is a temp variable that will help us hold on to the object that we remove. So what we're doing here is we're saying, create this temp variable and assign to it a reference to the object that this name points to. Why are we doing this? Because we still want to have access to the object outside of the aquarium. We don't want it to float off into code oblivion. We want to be able to use it or maybe place it on the table or something like that. Next, we will remove the actual property from the aquarium. That's with the delete keyword. Finally, we'll return the temp variable so that we can still have a reference to that removed object once the takeOut method is finished. Let's test our takeOut method. So we'll get a variable established here called fishOutOfWater and we'll take out a fish. Who are we going to takeOut? We'll take out Marlin. What happens is that Marlin's entire property is completely eliminated, and Marlin gets established inside the fishOutOfWater variable now. If we were to log out the fishOutOfWater variable, we can see that the entire fish object of Marlin is still available. But wait a second. That kind of sucks because we lost Marlin's name. So let's see if we can fix that problem with some clever property trickery. We're going to add an extra line to our takeOut method. This is going to make sure that we get Marlin's name when we remove him from the aquarium. Don't let this frighten you, but stay very close on it. The first name in this line of code will find the desired object in the aquarium, using the parameter name as the property name. So this bracket name is finding inside the aquarium, the object we're looking for. Then we use a dot, and that second name will create a new property inside the object that we want to remove. This is kind of cool. Notice, though, that .name is not the same name as the functions parameter. That's very important. This third name, however, is the functions parameter. It assigns the old property name, which we already know is Marlin, to the newly created name property in the removed object. How sneaky and cool is that? We love it. Now when we take Marlin out, and then we log out his variable, on the back end of our object, we see a new property name called name and Marlin's name is there. Woohoo, no identity crisis, fantastic. Now the cool thing about our takeOut method is that it will take out any object. We could delete even our Dragon Statue. So let's try that. We'll establish a variable called toy, and go ahead and take out the Dragon Statue. It shows up inside the toy variable, and when we log out the toy, this time, we can see, not only has the toy been taken out of the aquarium, but look at the back end, you can see the name was saved, Dragon Statue.
(music) Welcome back. Hope you enjoyed those challenges. And we're on to the third section of level four. We're going to try to count some fish in our tank. What if we wanted to know exactly how many fish we have inside of our tank at any given time? Let's take a look. So we've got our aquarium object and we just use some icons here for shorthand, but just know that those represent the objects that we've added or that were in there earlier. You'll notice that we put Bubbles up near the front with the other fish just to have a little bit better organization for this task. So let's count our fish. Let's see how many fish we've got going on here. The first one is the Nemo property and if we look at its type, we see that Nemo is definitely a fish. We follow that with Dory. Dory is also a fish. Bubbles is a fish. But Peach is an echinoderm. We call it a starfish. Not really a fish. Then we move on to the Coral Castle, and that's an environment. Well addCritter's a function, it's definitely not a fish, and takeOut, same thing, it's definitely not a fish. So three fish total, right? And how we did that sort of feels like a loop. So intuitively, we sort of think, maybe if we loop over the properties of our object, we could find out how many fish are in there just by checking the type. There's one caveat here, though, and that's that the aquarium does not have a link. That's completely undefined. It's not like an array where we can just count the cells using the links property. Because generic objects don't really have a native length like arrays or strings, we would not be able to use that length inside of a loop parameter. We need a different way. Welcome to enumeration using the for-in loop. It's a new kind of loop we're going to show you right now. The for-in loop will let us access each of the enumerable properties in turn. You might ask what enumerable means. For right now, you should just know that it means every object or property that we have added to this object ourselves. We'll go into exactly what enumerable means in a later course. So here we have our very special for-in loop. You can see the for keyword, which looks just like the for loop keyword, but inside the parameters of this loop, you can see on the left hand side, the word key, and in between the two words is in, and on the right hand side, is aquarium. Now key here represents every single property that is present inside of aquarium, and the in keyword will look in the object on the right hand side for every possible key on the left hand side. You can think of it like accessing each index of an array. Now if you were to log out each of these keys which you know are just property names, we would get Nemo, Dory, Bubbles, Peach, Coral Castle, addCritter, and lastly, takeOut. Something to note here is that our word key is not any special keyword or anything. We could use whatever name we want before the in keyword to refer to each property inside the object, such as, say, item or even the letter P for property, or any real intuitive word that you like. Think of it like a parameter that points only to the string names of the properties. The cool thing is that it's a name you get to create. For now, though, we're going to go ahead and stick with key since it's an often used word to describe the name of a property within an object. Now that we've got our enumeration set up, we need a way to determine which properties in the aquarium are actually fish. First thing we'll do is we'll set up a variable called numFish that's going to be our counter. Then we set up a conditional where we ask the aquarium, if the current key that we're on, which you know is just a property name string, has a type that is fish. Something to note here is that once we've accessed the object that the key refers to, we can just check out its type property to see if it matches the string fish. And if that's true, we'll go ahead and just increment our numFish variable. What happens, though, when we get to the addCritter function, which is way down there at the end of the object, and we try to access it, and then see what its type property holds? Well that's going to be undefined, so that's still okay because undefined does not equal fish, so we will never increment our numFish variable on a function. So let's check out how our loop actually progresses. The first thing that happens is that key becomes Nemo. That's our very first current property. And so our conditional looks up aquarium Nemo and asks, does it have a dot type? Does it have a type property? Yes, it does. Let's check it out, what is it? It's fish. So does type equal fish? Yes, it does, that's true, and our numFish variable is incremented to one. The same thing happens for Dory. It does have a type property, and that type is fish, so we get numFish incremented to two. And then when we do Bubbles, the same procedure happens and we get numFish incremented to three, but then we get to Peach, and it does have a type property but its type is not fish, it's echinoderm. So type is not equal to fish, and we do not increment the numFish variable. Same thing occurs with the Coral Castle because its type is environment. Lastly, we get to addCritter, and it doesn't even have a type variable so it will be undefined, and that will stay false when we try to check whether the type is the fish, and we will not increment numFish for either addCritter or takeOut. And if we try to log out our numFish variable, we can see that we have three fish inside of our aquarium. Now we've built all of this functionality outside of the object. We really want to put that inside the aquarium so that we can call an aquarium fish counter. So let's scoot our stuff over here and we'll go ahead and establish a new property inside of our aquarium called aquarium.countFish, and we'll assign a function expression to that particular property. Inside it, all of our code that we built. Now something special needs to happen inside of our code, though, because every place that we had aquarium, can you think of what we're going to place here? We're going to put the this keyword. That's right, because it needs to refer to the owner object of the function that's being called. Additionally, since we're building a function, we now need to return something from that function. So we'll go ahead and return our numFish variable. Magically, our countfish function appears inside of our aquarium object. And when we call aquarium.countFish, we get three, awesome. Let's take Dory out. We'll establish a poorDory variable, and we'll call aquarium.takeOut on Dory. Dory pops right out. We'll scoot our objects closer here. And the delete that happens inside of takeOut will return us a true, and now Dory is held inside of poorDory. If we were to now call aquarium.countFish, we appropriately get two because now there are only two fish inside the aquarium object.
Plains of Prototypes
Prototypes and Inheritance
Inheritance and Constructors
Overriding Prototypal Methods
Jason has been teaching since he was a kid and has racked up a bunch of Education degrees since then. A glutton for punishment, he's nearly finished with a Computer Science degree, too. He's built...
Released27 Nov 2013