What do you want to learn? Leverged jhuang@tampa.cgsinc.com Skip to main content Pluralsight uses cookies.Learn more about your privacy Code School: JavaScript Road Trip Part 3 by Jason Millhouse Build important intermediate skills within the JavaScript language. Start CourseBookmarkAdd to Channel Table of contents Description Transcript Exercise files Discussion Recommended Forest of Function Expressions Function Expressions and Anonymous Functions Hey Code School friends, welcome to the third edition of the JavaScript road trip. As you know by now, JavaScript is a very powerful web scripting language used all over the world in innumerable web based applications, and a knowledge of it is going to be an extraordinary asset to you on your journey as a developer. Now, if JavaScript is still sort of new to you, you probably want to go hang with road trips one and two because we'll definitely be taking several, if not all, of those concepts and layering them into the topics of this course. As far as new stuff, we'll be examining the fine art of the function expression, as well as the cool and often mind boggling use of closures, and then the impact of hoisting on load order. Ultimately, we'll wrap up with an introductory exploration of the awesomely important JavaScript object and then examine their blueprints in the form of constructors and prototypes. So with that, let's start the JavaScript road trip part three. From the Labyrinth of Loops to the Variable Valley, We'll see the Cliffs of Value first JavaScript's right up your alley Built-in Bluffs, files, falls, Array Archipelago Declarations in a desert, Where you'll find out how far you'll go Learn to program, take a ride Buy a ticket, step inside All aboard, you're at the station To increase your education Bon voyage and skinny dip As long as functions you don't skimp On this the JavaScript Road trip To start of this leg of the road trip, we'll be examining a special usage of a function inside of JavaScript called the function expression. Periodically when we code, we need to make an efficient choice about which function to actually build when our program loads. Typically we do this when we've received a special piece of data or when we need to build a one time, one run function for our websites. Also, we want to make sure that we do this without building every possible function that we could when our program loads in order to conserve program memory. Additionally, we often want to take functions and pass them to other functions. Or, we may want to immediately call a function as soon as it's built. And with that, we hope you enjoy traversing the forest of function expressions. Here we are in level one, welcome back to JavaScript road trip three. In this level, the first level, we'll be looking at function expressions, a pretty cool thing, which we like to call functions on the fly. In order to understand what a function expression is, we'll first need to look at what you already understand, which is a declared function. Check this one out right here. You can see here on this first block, a declared function called diffOfSquares. Now we've given it two inputs, A and B, and you can see that we've squared A and squared B and then subtracted them. See the minus sign in the middle. And then that's the value that we are returning. There's our declare function. This function, since it's declared, is actually loaded right when the program is run and it is loaded into memory and held there until you want to use it. Function expressions apply things a little bit differently. The first thing that we would do is we would establish a variable, let's call it diff. And then what we would do, is we would rearrange the declare function into an assignment statement. This particular thing is called a function expression and it loads only when this particular line of code is reached inside your program. Take a look, you can see the function keyword and you can see the diffOfSquares function name and the inputs all in the same place, and then the very same function body that does the same stuff that we had in our declare function. Again, this loads only when your program reaches that line of code. Another thing you should take note of is that since this is now an assignment statement, meaning we're taking this entire function and assigning it to the variable diff, we need a semicolon here on the end of our final bracket of our function body. In order to call our cool new variable diff, we're actually going to use the variable's name, that's right, it's going to be diff. We're not going to use the diffOfSquares name that's inside the function. Then we just pass two parameters to it. We're just going to give it nine and five. And you can see that that returns 56 'cause you get 81 minus 25, returns 56. Something to check out here is that I have given parameter parentheses to the variable diff. We haven't seen that before, right? And then we pass parameters into those parentheses that we've given to diff. We need those in order to actually call the function and give it some parameters. Now you might be wondering, why in the heck do we still have that diffOfSquares name if we're just going to use the diff variable name? It's an excellent question and guess what, we don't. Let's take a look at that. There is this cool thing in JavaScript and in other languages called the anonymous function. It means that you can build a function expression without a name because it's being assigned to a variable that will hold the entire contents of that function. Since we don't need that diffOfSquares name, we can go ahead and get rid of it. Let's get rid of it, there it goes. And now, we will just scoot the parameters and the first body bracket up against the function keyword and we have an anonymous function. Particularly, an anonymous function expression. Now guess what, just because it's anonymous doesn't mean anything, we still call the function with our new variable name and we pass in some parameters, four and two. That would give us 16 and four, and when we subtract those, we get 12. Now in our previous JavaScript courses, we've been logging out of tons of variables to see what they hold, to see what their contents are. What might happen if we did that with our new diff variable that holds a function? Well, as you might expect, you will get the actual function body returned as a result so that you can always check the contents of the variable to see what function it is actually referring to. Let's take a look and see how we can use function expressions, stored functions, in a national park terminal, specifically, at the forest of function expressions. One of the cool things about variables that hold functions is that they can be passed into other functions for use inside that function. Let's take a look at that. Say we had a JavaScript file, we'll call it terminal.js for the national park terminal. And we wanted to build a greeting for people that were attending, let's say the Badlands National Park. Here you can see we have established a variable called greeting and in that particular variable, we are going to store a function expression that will alert a message to the user. Thanks for visiting the Badlands, we hope your stay is better than most. Next, near the end of our file, we will establish a declared function called closeTerminal and what that will get passed is a function expression, the parameter name for it will be message, and then inside closed terminal, that function will be called. So maybe you can kind of see how we will use the greeting variable coming up. Later on in our file, after our customer has perhaps interacted in some other ways with the terminal, the closeTerminal function will be called and you can see that we passed greeting into closeTerminal. Let's take a look at what happens when we pass greeting to closeTerminal. Well, the message parameter becomes the greeting variable and then inside closeTerminal, the function that's in greeting gets called. Then we would get the alert message, thanks for visiting the Badlands, we hope your stay is better than most. One greeting is pretty cool, but what if we had multiple greetings? We could have multiple different kinds of greetings for different kinds of customers. Function expressions are very cool and very useful in this way because they give us a flexibility in determining exactly which functionality we want to store and then pass in later. Let's go ahead and scoot our stuff down. Now we are going to try to build multiple greetings. We'll establish our greeting variable, but we're not going to assign a function expression to it quite yet because we need to decide whether we have a new customer or an old customer. We've got some code that'll be there in our terminal.js file that will decide whether we have a new customer or an old customer and therefore, new customer will be true or false by the time we reach this conditional. If we have a newCustomer, then we'll go ahead and assign our previous message that we built to the greeting variable. But otherwise, meaning it's not a newCustomer, then we'll make a different function, and we'll say, welcome back to the Badlands, guess they aren't so bad, huh? That's for our old customers, people that have been to the Badlands before. Now you can notice that we have two possible greetings with one variable. Let's see what we can do with that. Now if newCustomer somehow was set to false by our terminal, we know that when we would pass the greeting variable into closeTerminal, we would get the old customer message, welcome back to the Badlands, guess they aren't so bad. And then if we were to also change newCustomer to true, we can see the message that comes up is exactly the old one that we had built before. (inspiring music) 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 (music) Hey everybody and welcome back. Just to review before we move on a little bit, we have built function expressions and assigned them to variables and then called the new variable, like we did here with some cupcakes. And then the next thing that we did, was we had an array full of values and then we built a function expression itself as a parameter for the map method. When we passed that function to the map method, the map method applied our function to every cell of our array and then built a new array as a result. You can see that here with our juices. Now what we're going to look at is how to return a function from a function, using function expressions. Say we had a mystery function, ooh, spooky. And then in there, we had some mystery code that we did a bunch of stuff, and then at the very end, we returned a function expression. That's what we're going to be looking at right now. Let's check out how we can return functions from functions using our special ticket system for our forest of function expressions theme park. Within that, we'll use an array as a queue for fast pass delivery. Let's check out the arrays that we start with here. We've got a parkRides array, inside are parkRidesarray we have sub-arrays, four of them to be exact, and in each sub-array, we see the ride's name, as well as the time that a customer currently would be estimated to wait for that ride. So you can see Birch Bumpers has a 40 minute wait, Pines Plunge has a 55 minute wait, et cetera. Next we have a fastPassQueue. Fast passes are organized according to whichever fast pass is available next, immediately next in time. The very first index of our fast pass queue shows Cedar Coaster, and that's because the very first fast pass that's available is for Cedar Coaster. And then it would go Pines Plunge, then Birch Bumpers, and then Pines Plunge again. Before we move on, we have to kind of understand how a queue operates. We're first going to build our queue as we see it here. The first cell that would be in our queue would be Cedar Coaster, let's say that's what we wanted to have as our first fast pass. And then what if we added to Pines Plunge to our queue? New items in a queue are always added at the very end of the array that represents the queue, just like in real life. When you get into a line, you go to the back of the line to be added to the line. Now we'll add Birch Bumpers onto the queue. But wait, we know a method that adds cells to the back of arrays, so what would we be using here, actually, in order to get that cell onto the back? That's the push method for arrays. You can see that if we add Pines Plunge with a push, it will go right to the back of our queue. Now we've built the queue that we see in our array, but we need a way to get the very first cell off of the queue because that's how lines empty, from the front. We don't have that method yet. Guess what, arrays have a very specific method for that process, that's called the shift method. When we call the shift method on any array, what happens is the very first cell of the array gets popped off the front and returned. Here you can see that if we call the shift method on our fastPassQueue, the very first cell would be chopped right off, which holds Cedar Coaster and Cedar Coaster would be returned. That shortens our queue just a little bit. What would happen if we called the length of our array? We can see that that will yield a three, and that's because the shift method, just like pop and just like push, will modify the length of the array automatically. Shift is cool because you can pop the front of the queue off but also store the result because it will pass back the result. It doesn't just let it fly away. Then if we were to shift again on our fastPassQueue, the first cell would get popped off and we can store it inside of a new variable that will call first fast pass. If we console.log that variable out, we will see Pines Plunge returned as the result. An important thing to note here about shift is that it's always going to return this first cell, regardless of whether you toss it away, like on the left hand side here where we just called shift and got Cedar Coaster, or whether you store it in a variable and then use it for something. Now, we're going to go ahead and use our queue to build our simple ticket system, let's check it out. Like we said before, functions can return functions. It's a very important thing about JavaScript. Since functions can be treated as expressions, we can return them like values. In our new ticket system, we will have a function called buildTicket and that will take in three parameters, the first of which we will call allRides. This will be the array of our rides, and of course their wait times, too. Then we will have a second parameter called passRides. This will be the array of all of those fast pass rides in order. Lastly, we will have the pick variable parameter which will be the actual ride for which our customer would like a ticket. First thing we'll do is check to see if the very first fast pass that's available, found in passRides If that's true, we'll just shift the very first cell off of our fast pass array and get it to a variable called pass. Then we will return a function expression that alerts quick, you have a fast pass to whatever ride they just got a pass for. Notice here that we're treating the function as an expression and returning it directly. It's not stored in a variable, nothing like that. It's just immediately returned as a function expression. Then, if the very first fast pass is not the one they're looking for, then what we're going to do is cycle through the entire rides array, all of the rides with their wait times. And inside that loop, we'll check whether the first index in each sub-array matches the name of the ride the customer would like to have. When it does, we will return a different function. This one says a ticket is printing for the ride and your wait time is about a certain amount of minutes. Now notice that the minutes are contained in the second index which is the index one of each of the sub-arrays in our array of rides. Now we know what our build ticket function does, let's see what we can do with it. If we establish a variable called wantsRide, that's the customer's wanted or desired ride, we have Birch Bumpers assigned to that right now. Then we will create a new variable called ticket to which we will assign the results of our buildTicket function. Notice that we have called this buildTicket function with the following parameters, parkRides, our array of rides, the fastPassQueue, which has all of our fast passes in it, as well as the wantsRide variable, which has the customer's desired ride in it. Later, when we call the actual ticket function, perhaps when the customer has closed out of the ticket terminal, we would need to put a set of parentheses on that variable and a semicolon in order to let JavaScript know that we want to call that variable as the actual function that it contains. As a cool result, we get our pop up that says this is your ticket to Birch Bumpers, your wait time is about 40 minutes. Why did we get this particular alert? It's because Birch Bumpers was not the very first ride in our fast pass array, and so we went ahead and issued that customer a ticket for the ride that they actually wanted. Now what happens when we change that ride to Cedar Coaster which is the very first ride in our fast pass array? When we call ticket this time, we'll see quick, you've got a fast pass to Cedar Coaster. Additionally, once that fast pass to Cedar Coaster has been printed, our fast pass queue will be shortened by one cell. Up to now, we have been storing our returned functions inside of a variable. JavaScript has a cool situation where you can immediately call the function when it is returned. Let's take a look at that. This time, we want Pines Plunge. Again you can see that that is the very first fast pass in our queue now. Now we're going to allow our ticket variable to disappear. We're not going to use that anymore. We're going to scoot our buildTicket function over, still using the same parameters. But what happens when we just call the buildTicket function without returning it to anything? What happens is it returns the function that it builds only. There you can see the entire body of the function as an expression that has been returned from buildTicket. And, nothing happens. Even though we got this function returned from buildTicket, nothing has actually called the function that got returned. If you look inside that function body, you can see the pass variable. The contents of that pass variable are saved in a process that's called closure. We're going to look at that in the next level, but for now, you just know that inside of this function body we have the first available fast pass which is Pines Plunge. Again, we've got this function expression but we need more in order to call that function expression immediately. Let's see what we need. If we scoot our semicolon out a little bit, and then we swish in some parameter parentheses, then the same thing would happen to our returned expression. It would also get some parentheses. Now we're kind of on the right track, we're getting closer to calling it, and once we scoot our semicolon back in, then our function expression with its parameter parentheses and its semicolon becomes an immediately invoked function. When that happens, what do we get? Quick, you've got a fast pass to Pines Plunge! How awesome is that? An immediately invoked function, no variable necessary. Our fastPassQueue shortens right up. Cold Closures Cove Tracing, Building, and Using Closures From the labyrinth of loops To the variable valley We'll see the cliffs of value first JavaScript's right up your alley Built ins, bluff, files falls Array archipelago Declarations in a desert where you'll find out How far you'll go Learn the program, take a ride Buy a ticket, step inside 00:00:21.07 Bon voyage and skinny dip As long as functions you don't skip On this the JavaScript Roadtrip - Hope you enjoyed all of those function expressions. Now we're going to move into a little bit more difficult territory. Every so often when we code we want to take variables from external scopes and bind them deep within inner or more local scopes of other functions. In JavaScript the tool that we use to do that is called the closure. Now, closures are often used in building function factories and sometimes they can be very hard to follow or very hard to trace, even hard to spot sometimes but after you've built a few of them you'll see that they aren't so bad. So, if you're ready to plow through the snow, head on down to the Cold Closures Cove. Hey everybody, welcome to level two of JavaScript Roadtrip Three, the Cold Closures Cove. Guess what? Congratulations, you've already made a basic closure. A closure is a packaged deal. Let's take a look at one that was in a previous example we showed in the last level. So, in the buildTicket function that we had in the last level you can see in our two returned anonymous functions several variables like pass and pick and allRides that were not created within the function that's being returned. That's very important. The entire contents of any of these returned functions will still be available outside the function, outside buildTicket when they get returned. When we return a function from a function and it is complete with variables that showed up in the external function, we have a closure. So, to kind of illustrate this a little bit better let's look at a very small example of a closure. A closure will wrap up the entire local environment complete with all of the necessary variables that came from an external scope. Here we have a function called testClosure and in it I've just established a variable called X and assigned the value four to it and then I'll return X from this function, a very simple function. Now, that X variable is only local, that means it can only be accessed inside of the testClosure function. So, let's take a look at that. If we were to call testClosure we'd get a nice return of four as you might expect because we returned X. But if I tried to access the X variable from outside the function I would get an undefined. That's because X disappears just as soon as the testClosure function is wrapped up. In other words, a function's local variables are just not available once the function scope has finally closed. Now let's make it just slightly more complex. So, now we'll establish that same X variable as four and then we'll build a new function inside of our testClosure function and we'll call that function closeX. Now inside of there we will return the X variable. And then outside inside of the testClosure function we'll return the closeX function. Now, here the inner function will be able to access the outer function's variables. Why? Because they feel like global variables to that innermost function. So, when I say return X inside of the closeX function, closeX kind of looks around in its own local environment for an X and it doesn't see one, so it look outside there to the global scope inside of testClosure, finds that X then assigns the four to the X inside of the innermost function. It's really important to note that X is not stored anywhere inside of the innermost function, not even as a parameter. So, now let's check out calling our external function testClosure and if we do that and we assign the results to a new variable, checkLocalX, we know that the entire function closeX, the innermost function, gets returned and assigned to checkLocalX. Now, let's check out what happens when we call checkLocalX. We get four. Whoa, that is crazy. This is interesting because even though testClosure has completely finished operating, it's scope is closed. We can still access the local variable that was declared in that function. Why is that? Because it has been bound as a closure inside of closeX. So, how can we use closures practically? Well, they're very helpful in what we call function construction zones. They make the creation of very similar functions very efficient, so let's see how this works if we were to try to make some transportation modes for the Cold Closures Cove. Let's say that we had a submarine to get across the cove as well as a battleship and then a giant seagull. Not only that, it is a pirate giant seagull with blue feet. Since we have these three different modes of transportation across our cove we can make a buildCoveTicketMaker for our different modes of transport. Here's our function and inside that function we would return another function that uses a name and alerts here is your transportation ticket via the transport which will get closed up from the external function, welcome to the Cold Closures Cove name which will be involved on a local level as the parameter. Now, our buildCoveTicketMaker function will make a ticket maker for every single mode of transportation, they'll be similar functions but just slightly different. So, if we wanted to make ticket makers for the submarine, the battleship and the giant seagull, we would establish three variables called getSubmarineTicket, getBattleshipTicket and getGiantSeagullTicket and we would call buildCoveTicketMaker for it. All of those variables. So, now that all of our variables have ticket makers inside them we can call getSubmarineTicket, getBattleshipTicket and getGiantSeagullTicket to see what's inside those variables. Well, look there, they have exactly the same function inside each variable but that's very deceptive because bound variables and their values will not be evident inside of a stored function, in other words, examining the function's contents will not show you a closure that has occurred. In our getSubmarineTicket variable transport actually holds submarine and of course in getBattleshipTicket transport is battleship and in getGiantSeagullTicket transport if giant seagull. Until we've actually called any of these variables that have functions in them, the named variable that is inside those functions will stay undefined, so let's change that. Let's actually call our ticket makers. Now, let's show how that works. So, we'll scoot our semicolons out of the way here and we'll pass in some names, Mario, Luigi and Bowser to our different ticket makers. What happens now? Well, Mario gets a ticket to the submarine and Luigi gets a ticket to the battleship and Bowser's forced to take the giant seagull. 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. Hoisting Hills Analysis of Load Order and Build Planning From the labyrinth of loops To the variable valley We'll see the cliffs of value first JavaScript's right up your alley Built ins, bluff, files falls Array archipelago Declarations in a desert where you'll find out How far you'll go Learn the program, take a ride Buy a ticket, step inside All aboard are at the station to increase your education Bon voyage and skinny dip As long as functions you don't skip On this the JavaScript Roadtrip - Ever have one of your programs produce errors not because your logic or your problem solving design is incorrect necessarily but instead because the load order of the functionality within your website seems to be getting in the way of your success? Turns out load order is a very important thing in JavaScript especially when parts of your program reply on other parts very heavily to succeed but can't find those parts exactly when they need them. Now, this level may seem a little short but don't let that deceive you because this packs on a very important bit of broader perspective for you as a developer and with that enjoy your hike in the hoisting hills. Hey guys, welcome back to level three, this is the hoisting hills. Now, in JavaScript hoisting is not something that you do, it's just something we want to make you aware of, it's a concept about program load order. So, let's take a look at this program right here. Now, you can see it's got three functions in it as well as two global variables and within that function two is going to call two subfunctions as well as initialize another local variable inside function two's scope. If all the stuff that's in function two work okay, then function two will be great and then if everything in the global scope works all right, then our program will be just fine. Sometimes though in the process of coding we produce a code order that doesn't produce a correct output because of the way that JavaScript prioritizes the loading of variables and functions into memory. So, now we're going to look at the load order in tandem with this concept called hoisting. For example, if in our function two local variable one needs subfunction two for something but it's not loaded yet, then local variable one will fail and ultimately function two would fail and if function two's failing, and our entire program depends upon it, then our program fails too. So, we're going to look at this load order concept, a concept we call hoisting so that you can always be sure that your programs run correctly. So, think about when we initially open a scope in JavaScript. The first thing that's going to happen inside that scope is that memory is going to be set aside for all of the necessary variables and the declared functions that the compiler sees within the scope you have built. So, let's take as an example this sumOfSquares function that you can see we're built here. Inside it, you see the variable X being declared and then assigned a value that comes back from an add function. And then that variable is returned. Towards to the end of the scope you can see the add function being declared just as a regular declared function. Now, that's what we see in our code when we write it but let's look at how JavaScript actually sees it when the compiler runs the program. So, the first thing that happens is that the variable X is hoisted to the top, it's given memory space at the very beginning of the scope initialization. But it has no value. The very first value that it has is undefined. The next thing that happens is the whole declared function is hoisted to the top of the scope and sits there in memory waiting for us to use it. And then and only then the executable code, the stuff that we actually want our function to do, that's when that gets run. Now, this is a great example of a function that works exactly as we we want it to work when it loads and when it runs but let's take a look at a few examples where hoisting has not quite the impact we would expect. So, first here we're going to build a function called getMysteryNumber and inside that function, we first declared a function called chooseMystery and it's going to return 12. And then following that we're just going to say return the result of the chooseMystery function. Then after that you can see I've declared another function called chooseMystery again and that returns seven. So, if we were to call getMysteryNumber what do you think happens in this case? A little tricky. So, all of this code loads like this in the compiler. The first thing that happens is the very first declared function gets hoisted all the way to the top, that's the first chooseMystery but then the lower chooseMystery, the one at the bottom of the code get hoisted also to be the second function in line. When that happens, the original chooseMystery function is completely overwritten, it is no longer there. Then the final and only executable statement says return the result of calling chooseMystery, so what's actually going to happen here when we call getMysteryNumber? We get a seven. Again, this is the case because all of the functions have been hoisted up to the top and then one was redefined, it's completely gone because of the second function. Let's take a look at another build of the getMysteryNumber function. This one's going to involve function expressions. Now, something to note here is that function expressions are never hoisted, they're always treated as assignments, so let's take a look. First thing I've got here is a variable called chooseMystery and I'm assigning to it a function expression that returns 12. Following that, here's my executable statement, the return statement of chooseMystery and then after that another function expression that's also called chooseMystery in the variable but that one returns seven. What do you think will happen now when we call the getMysteryNumber function? Well, here's how JavaScript loads it. The first thing that happens is the variable chooseMystery is hoisted to the top and memory space is provided for it and the value is set to undefined, so JavaScript has no idea right now whether that's going to be a number, a string, an array, or a function expression. Following that, the second variable declaration of chooseMystery is hoisted to the top which is also undefined and that completely overrides the other chooseMystery variable that was undefined. Then we arrive at an executable statement that is when the chooseMystery variable gets assigns a function expression, this one returning 12. Following that we see the executable statement return chooseMystery and so, this function is going to terminate at this line. It's actually going to call the chooseMystery function right now. And then this later assignment of a function expression to the chooseMystery variable is actually unreachable as a result of that return statement. So again, once we've returned we can never reach that code that's underneath the return statement. So, when we call getMysteryNumber, the only function expression that's ever been associated with chooseMystery by the time we return is the one that returns 12. Okay, so let's shuffle around the build a little bit and see how hoisting might impact this situation. What if we move the return statement up to the top? That's the very first thing that our function sees. And then we put our two expressions, our two function expression assignments down underneath the return statement. What do you think the getMysteryNumber function will return in this case? Let's take a look. So, the first thing that happens is the first variable that's ever declared which is the first chooseMystery you see on the left, that gets hoisted to the top and it's assigned an undefined value. Same thing happens for the second chooseMystery variable and the first one is gone, it's completely overwritten. Then we tackle the return chooseMystery statement 'cause that's the first executable code in our function but there's a problem because check it out, after that return statement, both of the chooseMystery assignments are completely unreachable because the function thinks oh well, I'm just going to return and call this random chooseMystery variable that he's assigned and as a result we get an error, so this function does not complete at all and never returns anything that we would want it to return, neither 12 nor seven. So, remember our train system from road trips one and two? Let's take a look at how hoisting might impact a capacity status function for the JavaScript Express. So, we will build a capacityStatus function that takes in the current number of passengers on the train, as well as the capacity for the train. Then if the train is full, we want to execute a function here that alerts a message that says no seats remain and then returns us a false so we know that we don't have any seats left. Next, if the train is not full, we want to execute a function that alerts a message with how many seats actually do remain and then returns true. So, what would this look like in code? Well, we would say if the number of passengers currently equals the capacity, that means we've got a full train, then we'll call a function called noSeats. Now, we haven't defined that yet but we will in a bit. Otherwise well, if the number of passengers doesn't equal the capacity we know we have some seats remaining, so we will call a function now called seatsAvail and that will tell how many seats are available. Now, let's work on those particular functions. First, we'll look at noSeats. What if we in our normal coding process just started to assign a noSeats variables of function expression? And we said alert no seats left, dude. And then we returned a false. Next, if we did the same thing on the seatsAvail function, and we just assigned a function expression to the seatsAvail variable, inside the seatsAvail function we would just alert a message that tells us how many seats are left for passengers and that function would return true. So now let's test this out. What if we called capacityStatus with 60 and 60? That means we have a capacity of 60 on our train as well as the train is full, we have 60 passengers. So, let's trace our code and see what the hoisting does in this case. The first thing that happens is the two variables that will eventually get function expressions are hoisted to the top and they will have undefined values. After those variables are hoisted, we have the whole slew of executable code, the first part is the conditional statements. If we have the same amount of passengers as capacity, we'll call noSeats otherwise we'll call seatsAvail. Following that happens the assignment of the function expressions. That's when noSeats and seatsAvail actually get their functions. So, do you already see the problem? Hopefully you already see the problem here because when we get to if the number of passengers equals the capacity, we will get a true on that because it is true that our capacity does equal our number of passengers and then the compiler will call noSeats but uh-oh, it doesn't even exist yet by the time that it is called. So, this function will completely error out and we will not have any message at all. So, well, we now know that hoisting causes problems, what can we do to fix these problems? Couple ways. Let's take a look at one. First thing we could do is actually change the order of our code. If we push all the variable declarations and their assignments north up to the top and all of the conditional code down to the bottom, the variable declarations will happen in the hoisting as well as the assignments will happen directly after that, so if we look at that capacityStatus test case again with 60 and 60, first thing that happens is the variables get hoisted to the top. They're both undefined but the cool thing here is that they immediately get assigned their expressions. Whoa, we like that. And then the conditional code is all the way at the bottom so we don't have to worry about any execution until everything's hoisted, all the assignments are made and then we can make an execution. So, now when we check to see if numPassengers equals the capacity, it still does, but this time when we call noSeats everything's fine, there's a function in the noSeats variable and we're good to roll and we get our nice alert message, no seats left, dude. Second way to fix this particular hoisting problem would be to not have function expressions at all. Instead we could have declared functions. We're going to try another test case here. We're going to put 20 in so that we can see how the else part of our conditional works 'cause in this case what? The number of passengers will not equal the capacity and let's see what happens in the hoisting of this situation. First thing, all the functions pop up to the top. They are loaded into memory and sit there waiting for us to use them. Again, the conditionals fall to the bottom because they are the executable portion of the code. Then we'll get a check to see if the number of passengers is equal to the capacity in our new case. It is not and so, we will skip that if statement and we will head straight to the else and we will call seatsAvail and guess what? SeatsAvail is already in memory, we'll get a very nice status that says there are 40 seats left, that's because 60 minus 20 is 40 all day. Ocean of Objects Object Creation and Manipulation From the Labyrinth of Loops To the Variable Valley We'll see the Cliffs of Value first JavaScript's right up your alley Built-ins wild file spas Array archipelago Declarations in a desert Where you'll find out how far you'll go Learn to program Take a ride Buy a ticket Step inside All aboard you're at the station. To increase your education Bon voyage and skinny dip As long as function's you don't skip On this the JavaScript (bright guitar music) Road Trip - Hope you've enjoyed those last few levels, and now we're going to take a little bit of a different fork in the road, and look more in depth at some JavaScript data structures, specifically, the JavaScript object. As you might expect, objects are a huge and powerful aspect of the object-oriented programming languages, and objects in JavaScript are no exception at all. In this level, you'll be looking at how objects contain multiple pieces of related data in one container, as well as how to access and manipulate that data, as well as how to build functionality that an object can own all by itself. Now this level's kind of chunky, but if you stick with it, it will soon be smooth sailing for all of your JavaScript object-oriented programming skills. So with that, it's time to dive in. Here's the Ocean of Objects. (bright guitar music) Welcome back. This is level four, the Ocean of Objects. Hope you had a great amount of fun hoisting your hearts out in the last challenges. Let's move on to exploring the object. What is an object? Well, an object is a container of related information. There will be multiple pieces of data, called properties, that are grouped within an object. Let's take a look. When we have an object in JavaScript, there are multiple properties that belong to that object. And we can represent everyday stuff with JavaScript objects. Since common things usually have these bits of related info, they will often make a really great object examples for JavaScript. So let's take a look at an object. This is called a book. You know what a book is, right? They're kind of dusty in the corner in your room. Yeah, those are books. Anyway, we have here some properties of a book. One would be the title of the book, that's a property. How about the author, as well as the publisher. The number of chapters, the number of pages, and the illustrator of the book. These are all things associated, bits of data associated with the book. We could also have a box. Some properties associated with a box might be the height, the width, the length, as well as the volume, the material it's made of, and whatever's inside it, the contents. Now because an object contains multiple bits of value put together, it's often called a composite value, because there are multiple pieces. Just like with everyday objects, properties can point to specific amounts or qualities for that object. So here we can have the height being six, the width is eight, and the length is 10. Therefore the volume would be 480. The material it's made of is cardboard in this case. Notice that's a string, and the contents could be this thing called booksArray, which is probably an array of all the books that are inside the box. Properties, as you may have noticed, can refer to numbers, strings, arrays, functions, or any number of things, including other objects. Let's try now to create an object with JavaScript. Now there are multiple ways to build objects in JavaScript, but we're going to look at an easy way, probably the one most often used. It's called the object literal. We'll start here by declaring a variable, we'll call it myBox, and then we'll assign to it, an empty set of brackets followed by a semicolon. Now the curly brackets say to make a new object in JavaScript. In this case, however, it's empty because we've got nothing in it. To add a property inside of an object literal, we give the property a string name followed by a colon, and then assign of value to that property. We can do that multiple times. The properties are just separated by commas. So we got our width now, our length, or our volume. Let's add the material, and we'll also add the contents but now, we will go ahead and list out an entire array for the contents. Sweet, now we've got a box object that's complete with all of its properties. A cool thing about objects, especially when you initialize them, is that they will accept variables. So if instead, we didn't want to put the contents as an array inside the myBox, we could build the array outside the object, and then just pass in the variable that holds that array. Now we've got a reference to the booksArray inside myBox. Great, so we've got an object. Well, what do we do with it? Typically, objects are used because you want to refer to their properties together. So let's take a look at how we can peek at a particular property inside of an object. Remember when we accessed the length on strings, and we used the dot operator? We're going to do that again here with objects. So if we wanted to find the width inside myBox, we would do myBox.width, and that accesses the property, and we get eight, sweet. If we wanted the materials to do the same thing, look it pops back cardboard as a string. And if we wanted to access the contents, we would do myBox.contents. And what happens there when we ask for myBox.contents? Well, myBox looks inside at the contents property, sees the booksArray variable, which refers to the booksArray outside the object, and that is what gets returned, the entire booksArray which you can see here. Changing property values inside of objects is one very useful aspect of objects, and we can do that with the dot operator. If we wanted to change the width inside of our myBox object, we would just call myBox.width again, and set that equal to 12, which will change the width inside the object to 12. We can show that by logging out the property myBox.width, which shows a very nice 12 now as a result. Uh-oh, though, that makes our volume incorrect. So we're going to have to do something about that. We're going to set the myBox.volume equal to the length times the width, times the height, which is what volume is, right? This is a good example of how you can use properties of an object to impact other properties within that object. And now we get a nice volume of 720, so everything is right with the world. What happens if we wanted to modify the contents of our box? We want to put a new book inside our box. Well, we would call myBox.contents, and that returns an entire array, the entire booksArray. And with that, we can apply all of the array methods that we already know from road trips one and two. So let's push on that array, On the Road by Jack Kerouac. You can see that, very quickly, On the Road is added to our booksArray on the outside, but whoa, how did that happen? How did we modify the external array outside of the myBox? The thing is that when we passed in booksArray as a variable, all that does is make a reference to the external array. It doesn't create a brand new copied array. Very important to understand. So that when you get that array back from myBox.contents, it's going to be the external array, and when you push to that, you're going to add it to the external array. Now if we were to log out our byBox.contents, we'll refer to booksArray, and we get the entire newly adjusted array. Also, just to show that we mean what we say, if we log out the booksArray, we will get the same exact array. Another cool thing about objects is that you can continue to add properties even after you have built your object literal. Even after that object is created, you can throw as many properties in there as you want. For example, if we wanted to add a weight property to the box, we could do myBox.weight, and set it equal to 24. When you do this, the myBox object is going to hunt around inside itself for the weight property, and finding none, it will create one for you and set it equal to 24. We could also add a couple destinations for the box. If we did myBox.destination1 and set it equal to Orlando, that would show up inside of our myBox, and then if we did a destination2, and said that was Miami, that would also show up. We've got a second way of accessing or creating properties that's just as important, and sometimes more important, than the dot operator. That's the bracket method. You can think about this as similar to accessing array indices. The thing about these brackets, as opposed to the brackets you use on arrays, is that you must pass in a string in order to reference the property. So here, if we wanted to find the volume property using brackets, we would pass in the string volume and it would give us 720. If we also wanted to find the material, we would do the same thing, and get back cardboard. You can think of an object just like an array but whose indices are accessed with strings instead of numbers. Here's a pretty cool thing about the whole bracket and string access. If you want to make properties that have spaces between the words, that's totally fine because the object just looks for a string and we'll find whatever string name you have provided, or create whatever string name you have provided. So here, if we wanted to add the number of stops that our myBox is going to make, we could do that with a nice string. Notice the spaces, number of stops, and set that equal to two. You've got to be real careful with those property names that have spaces, though, because if you try to log out myBox."# of stops", you'll get an error. That's because there's no such thing as a dot string. You can't access a property with a dot string. It's always got to be brackets string or dot, a string name with no quotes. In this case, when you want to access your myBox number of stops, you have to use a bracket. Yet another cool thing is that those brackets will accept expressions, and that's going to enable us to get dynamic property access. That's going to enable us to avoid hard coding every last property access that we would want. Let's take a look. So here we've got a for loop. We establish a loop counter, and we're going to loop over the entire amount of stops that our myBox goes through. And then we're going to log out each destination. How are we going to do that? We're going to access each of the destinations, one and two, by using a dynamic expression inside of the bracket. Notice that we've got a string destination plus the loop counter. Notice the loop counter starts at one. So as this loop progresses, we would get an expression, destination1 and destination2, inside those logs and what will we get? We'll get Orlando, and then we'll get Miami. In this way, you could continue to add destinations to your myBox, and it will be able to log out each one with this simple loop and the bracket expression. Here's where it gets interesting because our contents could actually be individual objects. Each book that's in our contents property could actually be its own book object. Let's take a look. First, we need to delete our contents property with the delete keyword. Let's see what we can do here. So there's the delete keyword and we say delete myBox.contents. Notice the syntax. What's going to happen here is that the delete keyword will completely delete the entire contents property. It will not be there anymore. It's not just deleting the booksArray variable and leaving the contents name there. No, property is gone. From our delete command, we get a true back, saying yes, we have deleted the property. If we now log out console.lot( booksArray ), we still get the same array. That's because we haven't actually deleted the array, we've just deleted the property that references the array inside of our object. Now you've got to be careful about that delete command because guess what? It's always going to return true. If I tried to delete myBox.nonexistentProperty, we get a true back. What? Weird, it was never even there. Now why is that? You should think about the delete command as asking, is this property gone after it has been deleted? So, of course, if it looks for something and it's not there, it's going to say true, the property is gone. Cool, now we'll build a function that creates book objects and we're going to add those to our box. Wow, this is going to be fun. First, we'll need a property that tracks the number of books that's inside of our box so we're going to go ahead and set that initially to zero. Our function will need it to dynamically assign property names in that bracket fashion that we just saw earlier. So here's our function. We call it addBook. We're going to pass in the box that we want to add the books to, the name of the book, as well as the writer. As soon as the addBook function is called, we want to immediately increase the number of books inside of our box. We'll do that with our bracket expression. Why our bracket expression? Because the string has spaces in it, so we want to be real careful there to use the bracket. And here's where the money is. Check this out and follow really closely. We're going to call the box with an expression that is dynamically made. And what's it dynamically made from? First, the string book concatenated with another reference of the box inside which is the number of books, so you can tell that when we call this very first addBook, we're going to get book1 out of it because the very first number of books is one. And then what do we assign to that new book property? We start up an object literal where the title property gets the name, and the author property gets the writer parameter. Cool, so there's our function. Now we're getting ready to add some books, let's do it. We'll call addBook and we'll pass in myBox because that's the box we want to add the book to. We're going to add Great Expectations by Charles Dickens. First thing that happens is our number of books gets increased to one, and we get a fresh book object inside of our myBox. Notice that the correct book number in the property name has been dynamically assigned. How cool is that? Next, we'll add The Remains of the Day by Kazuo Ishiguro. That will automatically increase our number of books to two, and add a brand new book number two. We see the title and the author assigned appropriately. Third, we'll put in Peter Pan by JM Barrie. Our number of books increases to three. We get a new book object called book3 as the property, and our title and author are just fine. And then when we pass in, lastly, On the Road by Jack Kerouac, we'll get our fourth book and our fourth book object. Now you might ask, well, if I've got a bunch of objects inside of objects, how do I get to those deep, internal properties that are inside the internal objects? Well, we can just use a subsequent dot notation to access those properties. So if I wanted to get to the title of, say, book1, I would use console.log myBox.book1, which pulls out book1, and then it looks at the title with that next dot notation. And what do we get? We get Great Expectations. Another way of doing that, of course, is with the bracket expression, so we could use myBox on book4, which pulls out the book4 object, and then looks at the author property inside of book4, which gives us Mr. Jack Kerouac. 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. Using Enumeration (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 (music) From the labyrinth of loops to the variable valley We'll see the clips of value first, JavaScript's right up your alley, Built in blobs, files falls, array archipelago Declarations in a desert Where you'll find out far you'll go Learn to program, take a ride, Come on and take a step inside, All aboard you're at the station To increase your education Bon voyage, skinny dip As long as functions you don't skip on this the JavaScript Roadtrip - Whew, you made it out of those, huh? I hope they weren't too challenging. But these might be. So in this level we'll be looking at the broad concept of inheritance, which is a very common object oriented practice. And specifically, we'll be looking at how it relates to JavaScript. Periodically when we code, we want to build a program that has a vast amount of objects, all of which share some small amount of similar functionality. Now we don't really want to build that similar functionality inside every one of those objects. Can you imagine the memory storage issues that might occur? So instead, JavaScript provides us with a very nice blueprint object that will pass those similar properties out to every single one of those objects that we have made. So saddle up, boys and girls and grab your lasso because you've reached the dusty and dangerous planes of prototypes. Watch out for twisters. Welcome back, this is a level five, the planes of prototypes. Surprise! Guess what? The objects we have built so far have some secret properties that we never saw or talked about. That's right, Nemo, Bubbles, the book, the box, the castle, Dory the and aquarium all have a bunch of properties that they were given just as soon as we created them. These are properties like valueOf, constructor, toLocaleString, toString, isPrototypeOf, propertyIsEnumerable and hasOwnProperty. Hmm, interesting. Where did these come from? All of these objects have a mysterious parent object that gives them some extra properties. We want to remove that mystery for you. An object's parent is called its prototype, and all of these methods that you see come from something called the object prototype. When a generic object is created, its prototype is going to pass it many important properties. So when we made that aquarium object before and put a whole bunch of stuff in it, the object prototype passed it tons of extra properties. A prototype is like a blueprint object for the object we are trying to create. JavaScript has a set of properties that it wants every object to have. And so the highest prototype, the object prototype, passes all those properties to every object. Passing down properties is called inheritance. Inheritance is a super important thing inside of programming and it goes a long way to helping us avoid overcoding. It helps prevent building multiple, multiple properties and methods that are exactly the same into similar objects. In other words, it helps us not have a billion storage locations for the exact same information. So far, all of the object literals that we've made with the curly brackets, they inherit directly from the very highest level in the JS hierarchy that's the object prototype. Turns out though that all of the JavaScript data structures that you can think of it will all inherit their properties and methods from their very own prototypes, not just the object prototype. Let's take a look. If I had an array and it has a bunch of strings in it, the array actually inherits from something called the array prototype. So all those array methods that we've seen or used inside of the previous Roadtrip course like length, pop and push and shift and some others, they all come from the array prototype. And those are passed down into the array object that we've created so that we can call each of those methods or properties on our myArray. Same thing goes with strings. If we established a variable called myString and we built a string inside of it, that string is secretly a child of the string prototype. And the string prototype passes a whole bunch of string properties and methods to our myString variable. That's how come we can call the length property on a myString as well as charAt and various other string methods. Similarly, the number prototype passes a few properties into every number. And lastly but certainly not least, the function prototype will pass a few properties and methods to every function declared or otherwise that you create. So are you ready for this? Not only do all those values inherit from their prototypes but the prototypes inherit directly from the object prototype. That means that the array, string, number and function prototypes, as well as all the other prototypes that exist in JavaScript have access to all of those object prototype properties. So coming back to myString, which inherits from the string prototype, not only does it get all the string prototype methods but it also gets all of the object prototype methods because the object prototype is an ancestor of the string prototype and thus, the myString. Now inheritance is really cool because it avoids a whole bunch of duplicate memory storage. So instead of hard coding all of those properties and methods into every object we could ever create, instead they inherit from one very nice location. But it's really important to recognize that though the properties are inherited, they're still owned by the prototypes, not the inheriting object. So what does that mean? That means that the properties that belong to the object prototype are actually stored there and they stay there and that's good because we want them to only be in that one location so they every object that we make can inherit from that one location. For example, the hasOwnProperty is owned by the object prototype so that when we would call it on myString, what happens is myString looks up to the string prototype to say hey, do you have this hasOwnProperty thing because I don't have it. String prototype says no, and so the search continues up what's called the prototype chain. When the search gets to the object prototype, the object prototype says yes I have the hasOwnProperty methods. And let's go ahead and let myString use it. Why? Because object prototype is an ancestor of the myString variable. Something to note here is that myString has access to the hasOwnProperty method without it needing to be stored inside the myString variable. Pretty cool, right? So the same goes with a common string property like charAt, which you've seen before in Roadtrips one and two. myString looks up to the string prototype and says yo, string prototype, do you have a charAt method? String prototype says yes I have a charAt method and you are most welcome to use it. Since the string prototype owns the charAt, the search is going to stop right there. The string prototype will grant myString the access to the function. Inheritance is pretty awesome. We're going to try to blow your mind a little bit here. What if we wanted to add some base values or some functionality to all objects of a similar type? Hmm, yes we can add inheritable properties to prototypes. Let's say here that we had a bunch of strings in whatever program we're working on and we needed to be able to count the amount of any letter within each string. For example, in these strings, if we wanted to know the amount of A's, we could see that which would have one; scarecrow, four; glinda, one; dorothy, one; lion has two; the wizard has four; and the tinman has five. Additionally, if we wanted to know how many E's were in these strings, we would get three, five, seven, four, three, five, five in order for those strings. Well that seems pretty easy, right, counting letters? But since this functionality doesn't actually exist in the ready-made JavaScript string methods, we'd have to build that functionality ourselves either in declared function or a function expression or something like that. Turns out though that we can add such a function to the string prototype as a property and then all of the strings that we build will have access to that property to use at any time. That's inheritance. That's pretty cool, right? So let's try it. We'll start to build a new function inside of the string prototype. Now this dot notation that you see here finds the prototype for all string values everywhere. To add our function directly to the string prototype, we're just going to use another dot and assign a new property name called countAll because we're going to be counting a bunch of letters. By adding this to the string prototype, we've now made it inheritable to all strings everywhere, even ones that already exist. So we'll assign to it a function expression and since we're giving a function to the overarching string prototype, we won't really need to pass the function a string because the string will be calling the function itself. All we need to get it is a letter. We need to make sure we give it a letter so that the function knows which letter we're looking for. Next we'll get a for loop going. Check this out. So inside we've got our loop counter set up and we're only going to run so long as we have not reached the end of the string. Now since the string we are interested in is going to be the very string that is calling countAll, we want to use the very important this keyword to refer back to that caller string. Now before, you saw that this was being used to refer to an owner, and that's because the owner was actually the caller of the property. So here you can see in a little more depth that the this keyword always refers to the calling object whether that caller is the actual owner of the property being called or not. Now here's where the money is. This is the conditional that checks to see if we have found the right letter as we move through the string. Let's look at the left-hand side of this conditional. We have this, which refers to the string that's calling countAll; and then we have charAt i. What's that doing? You know what that's doing. It's looking at a particular letter inside of the string. Then we have a .toUpperCase. That's a very cool and useful string method but how is that going to work if we only get a character back from the charAt method? Well, it turns out that charAt gives us back in fact a string that just happens to be one character long. Now toUpperCase will take any string, even one that is only one character long, and convert any alphabetic characters inside it to uppercase. You can see here that a lowercase bam with an excavation point becomes a Batman-style bam when toUpperCase gets a hold of it. Now why would we be doing this? Well, let's check out the right hand side. The letter.toUpperCase will return whichever letter we passed in as an uppercase letter. What does this do? It means that our comparison is only looking at capitalized letters the whole time. And that way, we don't have to have these complex conditionals that look for lowercase and uppercase altogether. We've taken care of it with one line of code. Something to note about the toUpperCase method is that if the letter you're looking at is already uppercase, it will just stay uppercase. So if we have a match, then inside that conditional we should adjust our letterCount to say yes, we have found one of the letters we're looking for. At the end of our function, we'll just return the amount of letters that we found. Great, we've added a function to the string prototype that all strings everywhere should now be able to access. First, let's try calling countAll on the witch string and let's pass in I as the letter that we are looking for. You'll notice there's an I inside isle, as well as in little for a total of two I's. Then we can call countAll on scarecrow. Notice this is a completely different string. That's because we added countAll to the string prototype. If we pass in o to our countAll method on scarecrow, we find the O's in some, people, without, do, lot, of and don't for a total of seven O's. Similarly, if we called countAll on lion with k, we would see the k in junkyard for a total of one. And if we called it on tinman with N, we would finally the N's in now, know and breaking for a total of three. Inheritance and Constructors (music) Welcome back, hope you enjoyed that set of challenges. You are now in section two of the planes of prototypes. And in this section, the first thing we're going to do is take a look at a second way to build objects using object.create, and it will tie in importantly with prototypes. Using inheritance, we can create new objects with our existing objects as prototypes. So here, we're going to go ahead and set up a new object, a new shoe, and we're going to give it a size, property, a gender property, as well as a construction property. If we wanted to create a new object that used shoe as a prototype, we'll create a variable called magicShoe, and we'll use the object.create method and pass in shoe. Whatever you pass in to the create method will be the prototype for the new object. If we logged out our magicShoe now, we would see that the object is exactly the same as the shoe object. It inherited all of its properties from shoe, just like we'd expect from our prototype. Now on this new object we could add a few properties, let's say jewels would be ruby. We could say travelAction would be click heels. Is this sounding familiar? And then the actions required would be three. And then we would get a ruby slipper out of it. Fantastic! If we logout the magicShoe now, you can see that we have all of the new properties added to our object. Just to show that our original prototype object has not changed at all, we can logout shoe and we can see that everything has stayed exactly the same. Let's take a closer look at the inheritance inside of our new shoe setup. We can actually use an inherited method from the object prototype to demonstrate our newly created prototype chain. Take a look at this line of code. It says object.prototype.isPrototypeOf. Do you remember that property from the object prototype isPrototypeOf? What it will do is look at the object on the left and see if it's a prototype of the parameter object. So in this case we're asking is object.prototype a prototype of shoe? Since that is true, the object prototype is in fact a prototype of shoe, we'll get a true returned from that method. Next, if we were to call shoe.isPrototypeOf magicShoe, we will also get a true. That's because we used shoe as the prototype of magicShoe. Now just to show that we don't always get true from this situation, if we called magicShoe.isPrototypeOf shoe, we would see that that is false. That's because a magicShoe is not at all the prototype of shoe. Now what happens if we call object.prototype.isPrototypeOf magicShoe? Well, you might think false because object prototype is way up there and magicShoe is way down there. But actually, this returns true and that's because isPrototypeOf looks all the way upward through the entire prototype chain to see if the object that's on the left-hand side is ever a direct ancestor of the object that's passed in as a perimeter. In this case, it only has to go two steps up to find the object prototype and so we get a true value returned. Cool, so now what if there were other kinds of shoes? Can we use the same prototype to create boots, sneakers, sandals or whatever that is. Well, let's check it out and see. So here's our shoe variable, right? We got a size six, we've got a gender of women and we've got a construction of slipper. If we decide to make a variable called mensBoot and assign to it the new object that comes out of object.create on shoe, what do we get? We get a mensBoot with a size of six, a gender of women and a construction on slipper. That's no good, that kind of sucks, we're not really getting what we were looking for here. Hmmm, what can we do about that kind of situation? Well, we might build a prototype that has just empty properties, all the properties that we want that are empty. Let's see what happens when we do that. We make our shoe variable have all those same properties but now set all those properties to undefined. Also now we have a prototype that's empty, but what do we do with it? Well, let's try making a mensBoot variable and assigning to it the object that comes out of object.create on shoe. What we get then is just an empty shoe object, right? And then we have to assign all the properties their specific values. We'd also need to do the same thing with the variable called flipFlop. We could create a shoe, an empty shoe, and then assign all of the properties. Guess what, this kind of sucks. You could see already how tedious this would be. If every time you went to create a new shoe off the generic empty shoe, you needed to put every single property in each one of those objects, that would be kind of terrible. And actually, all of that is way more code than it would take to just start out by coding an object literal and putting all the properties in your very first object literal. So we need a different way that won't be so cumbersome and that will automate our property assignment. Let's take a look. Pretty cool. First thing we need to do, we need to determine a whole bunch of common properties of a shoe class. What's a class? It's a set of objects that all share and inherit from the same basic prototype. So size, oh that's one that shoes should have, right? All shoes have a size. How about color? Yeah, that's all shoes. Gender? Yeah. Construction? Sounds good. How about laceColor? Well, some shoes don't really have laces. Look at this slipper or the flipflop doesn't have any laces, so let's go ahead and put that under some shoes. How about the function laceUp? Say if we had a function that laced up the shoes, does that belong to all shoes? No, because not all shoes have laces so we'll put that under some shoes. How about jewels? Thankfully not all shoes have jewels. How about bowPosition? Well no, I don't imagine there's many bows on workboots. How about putOn? Well yeah, we can have a function for all shoes that puts on the shoe. dimensionalTravel, like say for the ruby slippers. I'm pretty sure dimensionalTravel is just some shoes. Don't quote me. And takeOff, takeOff is probably an all shoes function. Now with a good set of these properties we can expect all of the shoes to have, we're going to be ready now to build what's called a constructor for our class. These other ones? We'd get to later. So now we will build a constructor function for our shoe object. A constructor is going to allow us to set up an inheritance, as well as assign specific property values for a specific instance of the object. That's pretty cool. Looking down here you can see we've established a function and we've called it Shoe with a capital S. That's important. Because capitalizing a function's name sort of distinguishes it in JavaScript as a maker of an entire class of objects. Now each of these parameters that you see here will be specific values for a specific kind of a shoe. The constructor function will construct a brand new shoe and then pass these specific parameters into that particular instance of the shoe. Now how will it do that? How will it take the parameters of the function and put it into a new shoe object? Well, we'll use the this keyword here. And again, that this keyword is very useful. That this keyword is going to have some unique behavior inside of our function. It's automatically going to refer to the new instance of the class that is made. So when we set this.size equal to shoeSize, as well as these other assignments, what's happening is the shoe constructor is building a new instance of a shoe and passing all of these parameters into that particular object from the class. We could also add some functionality here. Here's our putOn and takeOff functions, which we've assigned as function expressions. Inside one we've got an alert that says Shoe's on! And then in the takeOff function, we've got an alert that says, Uh, what's that smell? Important thing to note is that these functions will be common to all shoes everywhere. Now we got to figure out how to use the constructor to actually make the new shoe object. Well, we've got a new keyword here and it is new in fact. What we'll do is we'll establish a new beachShoe variable and we'll assign to it the object that comes out of the constructor function. How do we call the constructor function? You can see there that, that new keyword asks the shoe constructor to make a new instance with these particular parameters, meaning 10 and blue and women and flipflop. If we go ahead and logout beachShoe, we can see that we get a shoe object. Notice that the front of the object, its name has changed from object to shoe. That's because we have a shoe object; and inside of it, all of the exactly correct properties that we would expect, plus some functions. If we were to now call beachShoe.putOn, we'll get a pop-up that says shoe's on! That's because the putOn method is accessible to any shoe that we create at any time. We could even add properties that are more shoe specific later. For example, on a flipflop, there's two straps and we might want to add that there are two straps to that beach shoe. So we say a beachShoe.straps is equal to two, and it would add it right in. But wait, hold on, where's my efficient inheritance? Yeah, I don't see any, there's not any here. We've got an object builder but we haven't really used the concept of JavaScript inheritance that we were promised by the constructor. So far, tsk, it looks like our constructor just builds an object with a bunch of data values and a bunch of function. In other words, all the properties that each shoe has belong to that shoe. They aren't stored somewhere else and then accessed by the shoe. That's really important. We want to make sure that we have a normal inheritance set up here so that we can have really efficient data storage. Hmmm, do we see anything about our shoe that will be the same for all shoes? Let's check it out. Every single shoe is going to have those two functions. But why? Wouldn't it be better to have those two functions in one object that every shoe everywhere can access? Yes it would. So let's try that. First thing we need to do is assign a prototype to a constructor. That's right, a constructor is not a prototype, right? Constructor is just a function and a constructor has a prototype. So by setting a constructor's prototype property, every new instance that we ever make every time we instantiate an object, it will refer to that new prototype we've made for all these cool extra properties. So here with our shoe.prototype, we're going to go ahead and build a new secret object within the constructor function's prototype property. This will tell every created shoe to inherit from that object. You might notice something else here. We haven't drawn attention to it yet, but every time we've called any prototype at all, be it array prototype, string prototype or the object prototype, we have always called it as a property of a certain class's constructor function using the dot operator. That's no different here. We've got the Shoe.prototype ready to roll. Inside our prototype, we're going to build two properties: putOn and takeOff. Notice they take up property style now. To put some values in those particular, we'll just build some anonymous function expressions that alert our desired messages. Notice now that our shoe constructor gets considerably smaller, and that means that every object we instantiate, every shoe we make, will also be smaller. That saves a lot of data, especially if you're running a shoe store, right? By putting both of those functions in the shoe prototype, we force every shoe object to inherit those functions when it needs them. So let's come back to our beachShoe variable. We're going to create it the same way. And if this time we were to console.log beachShoe.gender, what happens is beachShoe just looks directly within itself for the gender property, finds it and logs it out and we get women. But then what happens when we do beachShoe.takeOff? Well, that's a method that beachShoe does not find in itself so what it does is it looks up to its prototype. What is its prototype? Well, that would be shoe.prototype. So it looks up there and it says hey shoe prototype, do you have the takeOff method? Shoe prototype nods and says yes I do and you may use it. As a result, we get the alert message, uh, what's that smell? If we were to call beachShoe.hasOwnProperty on the string construction, well, neither beachShoe nor the shoe prototype own that property hasOwnProperty. So what happens is we go up even another step back to the object prototype to find the hasOwnProperty method, and there it is. And the object prototype says yes beachShoe, you may use this property, here you go. But then what happens? The hasOwnProperty function now looks to see if beachShoe itself has the property construction, which it does! And so we get a true value out of that line of code. Now here's something very useful. Prototypes can actually refer back to their instances to pick up some data. Let's see about modifying our message functions with some of the data in our shoe objects. So let's go ahead and get rid of our current alert messages. So now in our new function, we'll say your, whatever style the shoe is, is on! Inside the takeOff function, now our alert message will say phew, somebody's size, and whatever the size is, are fragrant. What's important here is that the this keyword will look back down to the particular shoe instance that called the function and pull all of the property data from it. So if we call now beachShoe.putOn, we'll get: your flipflop's on instead of just your shoes on. And if we call beachShoe.takeOff, we'll get phew, somebody's size 10's are fragrant. Overriding Prototypal Methods (music) Welcome back folks to the last section of the planes of prototypes, hope you had a great time with all those challenges. And weren't they a doozy? Yeah. Let's turn to our next topic, useful properties in the object prototype. Yeah, remember all those cool object prototype properties that we saw at the beginning of this level? We're going to examine and use a few of those now. First one we're going to look at is the valueOf property. Let's say we had two variables, X and Y, one gets assigned four and the other gets assigned the string four. If we call x.valueOf, we'll get that property from the object prototype and we get a four back as a result. If we call y.valueOf, we'll also get the string for back. Now why are we trying to differentiate between these two pretty obvious things? We just want to make sure you know that the value in valueOf isn't looking for numbers necessarily but instead returns whatever primitive type is associated with the object. That's going to come in handy pretty soon. Now if we try to compare x.valueOf equal to y.valueOf, we get a true. Why is that? We need to be careful here. That's because the double equal sign tries to help us out, tries to be our friend by using type coercion, which turns a number contained within a string into that actual number. So here, the four that was in a string actually got turned into the number four. And so the double equal sign said yes, these things are exactly the same. But we didn't want that. Sometimes you might, but not this time. So why should it matter to us that the number four is different from the string four? Well, up to now in the JavaScript Roadtrip courses, we've always known that the two values that we'd be comparing would be exactly the same type. That was to sort of keep it simple for you to understand as we moved along. But as you grow in your skills as a JavaScript programmer, you're going to want to make sure that the types that you get, whether from files or from a user entry match what you're seeking. And so we need a different way to compare types as well as the values contained within those types. Enter the triple equals operator. The triple equals operator does not ignore the type of the value in the way that the double equals operator will ignore the type for us. So therefore we get sort of a truer interpretation of the equality here. And JavaScript experts will often prefer the triple equals operator over the double equals operator for this reason. Here you can see when we use a triple equals on x.valueOf and y.valueOf, we get a false. valueOf can be used on all native JavaScript datatypes. So here if we established a variable called a and assigned to it an array that contained three and then blind and then mice and we called a.valueOf, we would just get the array back. It's almost like logging out the array. Same thing with the number object, you can see the number constructor being called on six over there. And if we logged out the valueOf the b, we would just get six back. Now you might look at all of these responses and think they're just giving me what the variable contains so why wouldn't I just use the variable? It's true, these particular responses are not very interesting. What's interesting though is when you redefine the valueOf method for a class's prototype. Let's take a look. What happens when we call valueOf on an object that we make ourselves? Here I've declared a tornado variable and I've assigned it a function expression. Guess what, constructors can be function expressions too. I'm going to pass in a category, meaning the severity of the tornado, as well as the affected areas. That's going to be an array of cities. And then the maximum wind gusts. That's going to be how high the winds travel in this tornado. Next, I'll need an array of the affected areas. We'll call that cities. And inside that array, there will be other arrays. In those subarrays, in the first index will be the city; and in the second index will be the population of that city for use later. Now to create a new tornado object, we'll establish a twister variable and pass an F5, very strong, the city's array, as well as 220 miles per hour winds. If we were to call valueOf on our new tornado object twister, we would get a return of a tornado object with a list of all of its properties and their values. But look at the location property. It says array three. That just tells me I've got an array with three entries in it. It doesn't even tell me that inside that array is another array, so I don't even know what's going on there. In other words, the valueOf is trying to give me as much information as it knows about this object, but we have to be responsible for making that valueOf method better. How can we do that? By overriding a prototype's property. Let's check it out. So why might we override prototype properties? Well, there are many situations, as you might expect, that require special functionality that's different from the first available property with that name inside the prototype chain. But we want to caution you to think of safety first in this case for overriding, because you want to make sure that you don't override a property let's say in the object prototype level that will affect all objects everywhere, shoes, tornadoes, boxes, books. We don't want that necessarily for what we're about to do, we just want to override the valueOf method for tornadoes. So we're going to do that inside of the tornado prototype. Let's take a look. So therefore, to get a more informative result for the valueOf method on tornadoes, we just want to modify the tornado prototype. So what would be a good redefinition of the valueOf property for tornadoes? How about we make it the sum of all the potential people that are affected by this particular tornado? Let's try that. Now to make sure we only do this in the tornado prototype, we're going to call tornado.prototype.valueOf, which creates a new property inside the tornado prototype. Next, we'll assign a function to it, and inside that we'll create a sum variable that starts at zero, and then we'll have a loop that loops over every array inside the city's array. Each time we get to a new cell in the array, we'll add the population of people associated with that city to our sum. And at the very end of our valueOf function, we will return the sum of those people. So now if we call twister.valueOf, we no longer get that big long list of properties in the tornado object, instead we get 641,647 people, which is the sum of all the affected people inside of our affected cities. Take note that the valueOf is found now in the tornado prototype, and that comes before the object prototype in the prototype chain. So therefore, the valueOf method that's still in the object prototype never gets even looked at. What's cool about this kind of overriding is that our value will even update as the city's array is updated. Say the tornado spreads its damage to another location and we need to add a city to it, let's try that. If we tried to push a new city into the city's array with the new population of 130,045, what happens now when we call twister.valueOf? We get 771,692. Why is that? That's because since the city's array was passed in by reference, we'll always get an updated value for that sum every time valueOf is called. How cool? Moving right along to another useful prototype property, this one is called toString. Now the default responses to the object's toString method are often very uninteresting, especially on the JavaScript native types. But overriding it can be cool. Let's take a look at what the toString method does. Over here we've got our original X and Y variables with the same values. And as you might expect, calling toString on x just turns the four into the string four. Calling toString on y doesn't have much impact, just returns the exact same string. Looking at the array, a call to the toString on an array will just stringify and concatenate all the contents but separating each entry by a comma without any whitespace. So overriding toString on the array prototype is usually pretty desirable for whatever you're trying to do. Additionally, the toString method can come in handy on a function. If we established a new function here and assigned it to a variable double and then called double.toString, you can see that the entire function is logged out as a string which could be very useful if you ever need to concatenate an entire function as a string into some formatted printout. Now let's go and override our toString method inside of our tornado prototype. We want to do something cool with our toString method in a tornado. So let's bring back in our tornado constructor as well as our cities and our new twister object. And down here we're going to override the toString method inside the tornado prototype. You can see here that we assign it a function inside of which we'll start a list variable that is an empty string. What this is going to do is hold a list of the affected areas in the cities. Then we'll loop over all of the arrays inside the city's array. Inside of our loop, if we haven't yet reached the last city, then we just want to add the name of the city and a comma to our list. But if we did reach the very last city in our array, we want to use the Oxford comma style and have some good grammar and put, and the last city. Notice here that the cities are contained in the zero index of each sub array. Once the loop closes, we'll know that our list variable is complete, meaning all of the cities have been concatenated correctly into one variable. Then we will return this rather large string here that says this tornado has been classified as an, and then we'll put the category in for this particular tornado. With wind gusts up to, and we'll put the wind gusts in for this tornado. New sentence, affected areas are, and notice now we concatenate the list variable in. That will put all of our cities in one spot. Potentially affecting a population of, and now this is cool, we actually are calling our overridden valueOf method on this. So we will get the population placed right there. Let's check it out. If we call twister.toString now, we get a very cool representation of all the data that's in our twister tornado object. It says this tornado has been classified as an F5, with wind gusts up to 220 miles per hour. Affected areas are: Kansas City, Topeka, Lenexa, and Olathe, potentially affecting a population of 771,692. Cool, huh? Next up we're going to try to find an object's constructor and its prototype. And there are some inherent properties from the object prototype that provide ways for us to locate those nearest prototype ancestors. Let's check that out. If we call twister.constructor here, we get the entire constructor function back as a result. Now next if we call the .prototype property of the constructor function, we will get the prototype object associated with that constructor. Pretty cool. So there we can see both the constructor function, as well as the prototype object that has our overridden valueOf and toString methods. Something useful to remember here is that if a prototype object is defined for a class, meaning the class uses inheritance in some way, that prototype will always be a property of the class's constructor. And the constructor is just another function object with properties. Another way to access just the prototype would be twister.__proto__. Kind of weird but it will give you back the exact prototype object used for twister. Now that you know how to access the prototype and the constructor, let's take a look at the hasOwnProperty method in the object prototype. This method will help you identify the location of properties, where they are stored. Searching the prototype chains for potential overridden properties is something we do a lot and it becomes very easy with this function. What if we wanted to find the owner of a particular property? Well, we can build a function to do that. Let's check it out. So what if we wanted to be able to find a specific property within an object's prototype chain? Hmmm, we wanted to find which location held a specific property. Well, we can add that one to the object.prototype. That way, every object everywhere will be able to find any property that we want to look for. So here you can see we're doing object.prototype.findOwnerOfProperty and then we assign it a function. The function takes in as a parameter the property name that we're looking for. The first thing we'll do is establish a variable called currentObject, which will be the object within which we're looking for the property currently. And at first we'll assign it to this, which means the calling object. We want to start at the calling object to see if the property is there. Next, we'll hook ourselves up with a while loop that will keep searching the prototype chain until we've tried to go beyond the object prototype, which has no prototype, hmmm. So if we tried to access the prototype of the object prototype, we would get null because object prototype is the highest prototype that you can go. Then we'll set up a conditional in which we check weather, the currentObject has OwnProperty, the property name that we're looking for. And if it does, we'll return that currentObject. Why? Because if the currentObject has the property name that we're looking for, that means it is the closest object in hierarchy to the calling object, which means that's where it gets the method or the property from. Otherwise, if the currently examined object does not contain the property that we're looking for, then we need to proceed up the prototype chain to find that property. Hmmm, how do we do that? Well, we say that the currentObject should now be whatever the previously looked at object's prototype was. That helps us move up the prototype chain. Then at the end, if the loop back says we know we tried to get past the object's prototype and hit null, what does that mean? That means we never found the property in any of the prototypes throughout the chain. So we should go ahead and let ourselves know that and say no property found. So now if we call the findOwnerOfProperty on twister with the parameter valueOf, meaning we're looking for the valueOf property, well, twister looks inside itself as an object and doesn't see any valueOf so it goes up to the tornado prototype and there it is, the valueOf function. So our findOwnerOfProperty method returns the entire tornado prototype to us as the location of the valueOf property. Now if we call our function on the goToOz property, hmmm, well, we'll first check the twister object. Nothing there. And then we'll head up to the tornado prototype. Nothing there either, uh-oh. So now we'll trudge up to the object prototype. Still nothing! Finally, we'll try to pass the object prototype, but that prototype is null. Wump wump. But actually, that's cool because our while loop will exit and we'll get no property found. So we see that trying to find the goToOz property shows us that none actually exists for this particular tornado, which I have to say kind of sucks. Course author Jason Millhouse 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... Course info LevelIntermediate Rating My rating Duration2h 17m Released27 Nov 2013 Share course