What do you want to learn?
Skip to main content
by Bianca Gandolfo
Resume CourseBookmarkAdd to Channel
Table of contents
Object Best Practices
Storing Data and Object-literal Notation
Objects Exercise Solution
Arrays vs. Objects
Access and Assignment
So those are some things that are kinda cool about arrays, that make them just like objects. And we were just talking about this loop, this for in loop, that we can use with objects. And if an array is an object, shouldn't it work? What are our predictions? Is that a prediction? OK, I'll get to you in a second. What's your prediction, what about, let's see. What about Kevin? Do you have a prediction? Log the values? The values? Yeah. Or the property names? The values. The values. OK. So we have a guess for the values. What about Andy? The property names. Property names. If the rules don't change, it's property names. Yup. So it's going to be the property names, because the rules don't change. And if you don't believe me, you can try it out. And the rules don't change. Check this out, our 0th numerical index is actually a string. That's interesting, right? So the rules don't change. And we can, we can, oh did you have a question, Mark? I'm sorry, I forgot. Yeah, do you have the chat up? It might help just to look at questions and double back now, but any difference between, and they have a few examples there. So the question is, is there any difference between... Here, I'll type it out here on the screen so everyone can see. box2 and then, so we have box.asdf = true. and then box2.asdf = false, I'm sorry, equals true. And this says, is there any difference here? And I'm going to argue, no that there's no difference between how we're adding a property and a value to an array versus an object. I'm going to argue that that is exactly the same. Even though it's an array. Cool. So we have this loop, and this k is printing out again, just the property names. So how would, if we wanted to get those values out, how would we do that again? What about, Grace? You would add a reference group with brackets. Absolutely. Cool. And so that's going to then log our values, which would be 9, and meow, right? Thumbs so far? Thumbs, thumbs in the back? Thumbs. Cool. All right, what about this, what is this going to log? Anyone? Nine and-- The values. The values? Good guess, but remember that whole variable dot notation rule? Remember that rule? Thumbs if you remember the rule? That you can't use dot notation with a variable? Thumbs? Thumbs? So since k is a variable, we can only use bracket notation. I'm just going back to this rule that we discussed earlier. So this is going to be actually undefined. Undefined. Because k is a variable. And if we go back to that slide, the rules? all the way down down down down down? That for, dots, we can't use variables. For brackets we can. Here, so. Cool. And we know, again, we know k is a variable because we just see var here, right? For var? That means k is a variable. Cool. So this is how we would do it then. Here we have the bracket notation. Cool. Cool, so. That's great. It behaves exactly the same as an object. Then how come we've never really noticed that before? Like when we loop right, we don't really use the for in loop because we're not really interested, and usually we're, if we're using an array, we're usually not interested in those named properties, so even if we did have this size here, this size property, we're probably not too interested in it, and if we were, we'd probably choose to use just a vanilla object. So how are we going to loop? We're probably going to use a loop like this, right? Has everyone seen, thumbs on this loop? On this for loop with semicolons here? Cool. So this for loop with semicolons is pretty interesting. Remember when I said the for in loop was like a thing that was made specifically for objects? That's not true for this for in loop. This for in loop is just mathematical, if you look at it all, how you give directions to the for loop is just this signature right here. We have for and we have var i = 0, so that's saying, create a variable, i, start at 0, and then it says loop, while i is less than the length of our box, right? And then this one says increment i plus 1 every time. So every time you loop we're going to increment i. And we could change that, you know. We can do plus equals 2 if we wanted. If you want to do every other one, or every third one. Right, you could change it. But i++ seems to be the norm. You could also count down, right? i-- But the mechanics here is that it's, they're just numbers, right? So if we console.log i, what is that logging? 0, 1, 2, 3? 0, 1, 2? Yeah. 0, 1. 0, 1. We're going to get to the length property in a bit, but the point here is that i just a number. Like, i doesn't know anything about our array. The only thing it knows about is this number here, box.length, which we could really just change to 2, and it would be equivalent. So there's no relationship between this loop and the array. It's just like mathematical directions. And so if we say increment until 2, it'll just console.log 0 and 1. Thumbs on that? Cool. What about this? Actually, hmm. I have a question. Sure. So, why is length 2 and not 3? We're going to get to that in just a second. Yeah. Let's just do this. So, if we wanted to access a value, could we do it this way? No. It's a variable. Yeah. I'm going to drill this into you until everyone, like, hates me for it. So here we have again, just our bracket notation with a variable, and maybe we're starting to see that i is just a variable, and we have to use the bracket notation only because it's a variable, not because the array is an array, and there's some special syntax surrounding it, it's simply because it's a variable, and also if we go back here, to box at 0, for numbers, remember, numbers we always have to use a bracket notation. And that's why you tend to see bracket notation with arrays, because we tend to use them for their numerical indices, and bracket notation just makes sense. So when I loop through that, my output is meow, and then whoohooo, so what index is the size or is the value 9 at? Yeah, so if you look down here, you can see, kind of think of it this way. So we have 0, we have 1, and then we have size. It's not at an index. It's just a property on the object. Oh, it's a property. Yeah. And so, since we're looping until 2, and i is a number, it's just going to be and i is remember going to be 0, 1, so it's going to say box at 0, right? Which is meow. You can think of it like this too. Or, box at 1, which is going to be whoohooo, because we pushed that onto the end, right? And so we see we have this property 1, with the value whoohooo. Does that make sense? We have size with the value-- And then we have size, which we don't touch, right? Because i is just a number. All right, can I have one question from the audience? Why would we use arrays instead of objects when it's pretty much the same thing? So why would we use arrays instead of objects? Because arrays have methods on them that deal with order, and you can sort them, you can slice them in ways that you can't do for an object. Objects are better for other things, like quick lookups, or having data with like, that is categorized, like if you had like, a user, just like your animal user, it has different categories on it. You know, you have a username, then there's a value there, and you have like maybe an age, and then it has a value, versus an array, if you tried to represent a user data as an array, it likes the name and then the age, it just, it's hard to keep track, you'd have to keep track of like the index, kind of. Like if you're using an array in a traditional way. Aren't, typically, I guess it depends on the processor, but iterating over an array is faster? Is that true? You know, I'm not sure, I haven't tested that. Well there's like a test thing I found, and in my browser, it is. By like, quite a bit, actually, so. Interesting. I don't know if that's true. I guess it depends on the browser, and how they implemented their engine or whatever. Yeah, that kind of makes sense to me. Cool. So what is the like then? Mmm, let's see. How many, I'm almost there. OK, wait, I actually am there. You just, we're coming to this. So the cool thing, so I'll just jump into this unless we have any more questions about iteration. Think this might be the answer. So there are a couple things behind just you know, but, so, if i is less than 3, it still wouldn't print size? True. True, because, the reason is, it would just, so if we just change this to 3 here, what it would print would be, meow, you know, whoohooo, and then undefined. Because what it's going to do, once it gets to the index 2, so once i is 2, it'll say box at 2, and it will do a lookup at our box, and we don't have a property at 2, right, we only have a 0, we have a 1, and then we have a string size. So it's never going to return size in this loop. And this is a loop we tend to use because again, when we're using an array, we're not usually using it to have numbered, or string properties, that are characters like size, for example. So what, in the console it identifies, and I put size, like you'd have size 9. And then I have 0 in quotes, and 1 in quotes, and when I just hit box, the size part doesn't come out. True, so the console like, just prints what it, it depends which console you're using, and the version of Chrome and all of that, but, for example, I have three undefineds. Let's see, so we have box, oh, that's because, yeah. Look at that, this needs to be i. Cool. So if we look at box, it appears just to have two things. But if you actually if you console.log box, sometimes you can see, let's see. So size is there. It's just not at a numerical index. And your console probably isn't going to pay attention to it because it's assuming that you are only worried about the numerical indices, and it's really up to whoever is designing the console, so what it's showing, what it's not showing, because really under the hood, there's a lot of different methods and properties on everything. Especially natively, that it's just not going to print out. And that same thing with length, like length of 2 and I just hit, not when I do console.log, but. Do you have a question? I just want you to verify that arrays stay ordered and objects don't? So the arrays are only ordered because of the numbers. Because it starts from 0 and it counts up, that's why there's order. There's not, nothing like magical happening, that like is keeping track of the order, it's just the numbers.
So, that second line box, square bracket size = 9. Uh-huh. There's no way to get that value out by using indexing with integers? True-- true because the only way you can get the value 9 out is by looking up, looking it up by the property name, which is size, which is not a number, right? Arrays can be accessed by index number as well as property names? Yup. So here I am using dot notation. box.size, box If you look at box. And then we have our numerical indices as well, we have meow, we also have whoohooo. Is it better to say arrays can have properties and indices? Mmm, I don't, mm, I'm not sure. Is Box an object that has an array as a property? Or is it an array that has a size that--? Box is an object. It's an array, but an array is also an object. So it's both an array and an object. And the thing that's special about arrays is not really the numerical indices, it's really the properties and the methods that come with it. So that .length property is something that makes arrays different, and based on the .length property, you can calculate a lot of things, so as long as the array, so if you have an object that's keeping track of the length, and then you have the methods, the array methods, that are working off of the length, then you have an array. So you can create your own array just by having that magical length property that's keeping track of the length. And, so how the length property works, it's only going to keep track of the highest numerical indices. So it's going to ignore size, it's going ignore itself, like length itself is a property, right? See we have this dot notation box.length? You know it's not counting that, it's not counting box.push, you know, pop, things like that. So it's only going to be keeping track of those numerical indices, and based on the length, and the numerical indices, those methods can do cool things with the data that we have stored in this array. Slash object. So if box is an object, then length would be three. Is that right? Well, objects don't have a length property. Oh. Yeah. So because arrays are objects, let's say you have an empty array and you're assigning meow to the first index. Behind the scenes does it add a property called 0 and then the value called meow or whatever you're assigning to it? Yup, that's a perfect way to think of it. And that's kind of why I draw it like this. You can kind of see, this is kind of how I think about it, that it's just an object and it has these properties on it, and it has the length property and a bunch of methods that give us some powerful functionality, like we can sort things, we can reverse it, slice, all those things that you can't do with an object. Yeah. So when you're console.logging you're actually logging the object? Mm-hmm. So that's why it shows the size. And that's why we could use it for this other for loop, remember, the for in loop will work with, will work with box even if it's an array. And that's because, because it's an object. (quiet question from the audience) Yes. In that case you do because it's just going to be looping through all the property names, that includes numerical properties as well as named string properties, yeah. Oops. Cool, you had a question? There was a question on why you would want to add a property to an array. Um, For different reasons. This will, it depends, you can add methods to it, to the prototype and things, that will add, you can extend functionality that way. You can, I don't know. And then I guess following from that, another question so if I have an object with an attribute called length push pop, etc., it will be an array? Yeah, so if the length property is keeping track of the numerical indices, every time you add something to it, then yes. If we use object notation when you add those properties to it then it's not going to make it an array. You can, you can mimic an array functionality. You have to build that into your-- Well that, that's what he was saying, if you do build it out, they're both objects. Right. One's native, one's not. The only hard part would be keeping track of the numerical, so you'd have to have some way to know whenever you're adding a property, to the object, so that you could adjust the length property. So. You'd have to use a get or a set or something. Adding the length property to that doesn't make it an array, you're not going to pick up automatically pop, push, slice. You'd have to build all that out. You'd have to build all that out, all that functionality. Yeah, right, it's a little more complicated, but. Cool. Sweet. All right, what about this? What's this going to log? So is it even going to work? No. Why? Because length is in quotes. It's looking for that. Because length is in quotes? What is length, so length in quotes again remember, it's the same as dot notation. Right? True? Length in quotes the same as dot notation, thumbs on that? Cool. So the length is 4. Right, and that goes again to like how length is working. So length is keeping track of the last index. It's not keeping track of like the number of, of actual values in the array. They wanted me to ask you, in theory you can get away with never using dot notation and only using bracket notation? True, you can, you could only use bracket notation. It's just more to type. Cool. What about this? What if I change this? Undefined, because length does not have quotes around it. That's tricky. That's not fair. I know, I just, you guys should just know that I'm tricking you the whole time. And look out for that, and think about those rules. And as you're coding you should be actively thinking about the rules. Is, you know, is this, you know, series of characters, is this a string? Is this a variable? Is it an expression, that needs to be evaluated? You should always be thinking that and keeping track of what it is. And then if it is a variable you should also be keeping track of what that variable can represent in different scenarios. All the time. Can't just take it for granted. Can you go back one slide again? Sure. What did you say at the very tail end of this explanation, you said it only looks at the last-- Yeah, it looks at the last or the highest, the highest numeric index, and then it adds one. Because the length is always plus one. Because it's zero-based. Because it's zero-based, absolutely. That's weird. That's programming. (laughter) Yeah, when I tell some of my students, you're my number 0 student. (laughter) Let's see, so we did that one, and then, here, so what if we, what if we, what if we wanted to find the last, we wanted to look at the last index of our array? Minus one? Like this? The length? Just minus one. That only works with slice. You're thinking of slice. Box.length? Box.length-1, totally. So box.length, right, is going to be 4 and then our last index is 3, as we can see here. So we need to subtract 1, and remember back to the thing about the bracket notation being able to evaluate expressions? This is a perfect example of when you'd want to do that. So here we're doing a property lookup, and we're doing math. So all those things are happening, and those are things that you cannot do in dot notation. And it just looks weird, right? Like, look at this. Right, it just doesn't look right.
So, actually I'm going to do nesting in a minute. And it's going to be exercise time. So again we're going to jump right to the exercises. We're going to go to arrays. And this is a little bit, a little bit longer, so maybe 30 minutes, let's say 40 minutes, let's do 40 minutes for this one, and we're going to create our second data structure, which is going to be a collection, which is going to be an array of our animal objects. And that's how we're going to be representing our data for our application, for eFarmony.
Arrays Exercise Solution
Anatomy of a Function
So now we're going to look over some functions that you may or may not have seen before and kind of like identify the parts of these functions. So we have four of them. Some of them I took from jQuery-- has anyone here done jQuery before? Okay, cool. So a lot of people have done, done jQuery. So the first thing is the function definition. So where do we see some functions defined? So let's just go in a line. Let's start with the front, this way. At the top, there's an anonymous function being assigned the nameImprover. Yeah, so we're defining a function here. And then, Rich? We're looking for where we're assigning functions? Where we're defining functions. Defining functions? It could be assigned in a variable. It could be anonymous. Would that be the body hide? Nope. Down there. Close. No clue. Right there, that's your next one. We're defining a function there. It has no name, and that's okay. That one doesn't have a name? Yep. There's no name. Oh, it's just passing val? Mm-hmm. So it's a function definition. It's also an argument. Yeah. And who sees the last one? Tanner? There's a function on click there. Right here. Function definition. So these are the function definitions in this code. Oh, and just for clarification, nameImprover function is this handy function that we use. At Girl Develop It for when our friends have babies or they have names that need to be improved. Body.hide is a jQuery thing that's just going to hide the body. So if I just did you'll see here. Wait, is that even jQuery? Yes. Oh, no there's not jQuery. Let's see if it works. Oh, cool, so it does work. So body.hide will just hide it and then .show will it and then array.foreach, foreach is a native, like, iteration method. It's going to just loop over the array and call this function a bunch of times and then button on click is another jQuery jQuery functionality and it's just adding an event listener so whenever you click on the button it's going to console log this. This "Don't press my buttons". So that's just an explanation of what functions we're looking at right now. Cool, and so what about function names? And I use name a little bit loosely. I refer to it both as like the function, the name function as well as like a variable that repre, that has a function stored at. So let's talk about where do we see function names? So can we start with just Grace and we'll just keep going? So you can anticipate when you have to go next. I don't see a name. For function? Yeah, so like, here for example would be a name. Oh, okay. That's the name for the function Yeah. versus the variable. Yeah, well it's a variable. I'm using name here loosely to mean, like, both the variable name that it's stored at and the name itself, yeah. 'Cause there's another way, like, we could write function like this function nameImprover, name stay same. So this is another one. So here's, this is just a really complicated algorithm that will just keep your name the same versus this other, this other one that will change your name and make it better. So this is another way to name our function. Is that the same as is that the same as the first declaration of a function, where, in the sense that you're adding var in front of it, versus adding it to the global? I don't know if that makes sense. So when we name-- Do you never want to do that one that you just did? The same stay name or whatever? I don't know. You could do it this way. The only thing about doing it this way is that your function name and definition is hoisted and that can be, like, if you, it can, like, get messy. Yeah. So it can get messy. So I just recommend that you always just use this one, 'cause you just, you know that the rules for variable hoisting and things are the same, you don't have to keep track of this and, Okay. Yeah. There are some situations, like if you have two functions are the same name in the if else statement, and then you run it after the if else statement, then it can get mixed up and do things that you don't expect because of the way hoisting works in this case. Okay. So you can do it, but you just have to be careful. But just to be on the safe side, just always do it this way. It's not going to hurt you. It's just var, just use one extra word, and it's not going to make a big difference. So, okay, so back to where we were. Here is a name, then we also have a name here. And then William, see any more names? Well you just added one called nameStaySame. Mm-hmm, what about, any other ones? I don't see any other ones. What about hide? That's a name, right? Yeah, yes. Cool. Kim, do you see any name? On. On, absolutely. On is a name. And Andy? Foreach. Yep, foreach is a function name. Joe? Log. Yeah, log. See, are we missing any? Oh, there's one more. It's kind of a trick question, though. Anyone see it? Dollar. Yeah, dollar sign. So this jQuery dollar sign is actually a function. It's not a special syntax. It's just a function. So you can imagine that jQuery, somewhere in its library says var dollar sign equals a function and then, you know, it, like, returns like a jQuery object somewhere, right? Oops. More like this. So, some things that may seem a little different are actually following the same rules and I find that very comforting actually. To know that. That jQuery isn't doing something like totally crazy that I don't understand.
Now what about function bodies? It's a little bit different than a function definition just because the body is what's located between these two parentheses. I'm sorry, these two curly brackets. And the important thing, while you guys are searching for more function bodies, the important thing to note about a function body is that it's never run until call time. So the code located within those curly brackets is not interpreted until you call the function so in this case, for nameImprover, since we're never calling it, this code here, never runs. And it has no real value. Cool. So let's see, who is next? Is the body before the .hide? The body? Not quite. So we're looking for two curly brackets. That's how we know it's a function body. Unless it's an object or an if statement, but on this slide. How about after function val? Yeah. So right here. We have a function body. And then Ben? In the on function, the second parameter is the, yeah, and then starting at the. Yeah, so right here. That's a function body. And Jake, what's important to remember about function bodies? They they are the verbs. Functions are verbs, that's true. You can, what's it called? Phone a friend. (laughter) Oh, I can keep 'em coming. Kim, help me out. My lifeline. What was the question? What's important to remember about function bodies? They're inside brackets. Yes, that's true, but there's something else. I'm looking for like one specific thing, anyone remember? They're not called 'til-- Doesn't call-- Yes, so it's not run until we call the function. Awesome. Cool. Speaking of calling the function. We have this thing called call time invocation so just for fun we can like we can improve someone's name. Oops. Uh oh. Okay. So I'm just going to put this function here and notice, I just put nameImprover there. We have it. Right, when I type out nameImprover it shows me what the function looks like. That's not call time. That's just me checking what is stored at that variable, just like when we say var X equals two and I just type X, it returns two. Same thing. So How many people here really love their name? No? Everyone? Okay so then we have three people who really love their name, so everyone else could use some name improvement. So everyone else just volunteered. (laughter) Full of tricks and traps. I mean, it's Halloween time, you know, it's time for those things. Okay so of those people, all right, you can recommend a friend. Who wants to nominate someone? Tanner. Tanner, okay. Thanks. (laughter) And who has an adjective that I can borrow? It has to be a nice one. It can't be like stinky or something. Buff. What? Buff. Buff? Okay. Buff. Nice. Awesome. So Colonel Tanner McBuff Pants. Nice. You can call up your lawyer and arrange a new name if you want. I know it's way better, right? I'll get right on it. Yeah. (laughter) All right, I'm going to call you that for the rest of the day. I appreciate that. Yeah, no problem. So notice here, so we have let's just look at the inside of our function. That we have our parameter here, name, and our adjective here, and they have no value until we pass these parameters, Tanner and Buff, right? And then suddenly they have value and suddenly the code in this line, in between the, inside the function body, gets called. And so that timing, that order, is really important. Cool. So Where else do we see call time? Hide. Yeah, hide, there is a perfect example. So we're calling hide. Where else? So where did we leave off? So we had Jake and then Kevin. Where else do we see call time? Foreach. Yeah, right here, absolutely. And then, Kashor? On. Where? On. Yeah, on is call time. Ah, let's see, so I guess we'll start again at John. Dollar sign. Yeah, so here we're calling jQuery. Anything else? Oh there's one more. There's log and val. Yeah there's just log. So console.log. There's two of them, so. Are you saying call time is another word for invocation? Yeah, exactly the same. But not on val because that's just a function? Val here? Val-- That's a parameter. Parameter. That's just-- Oh that's a parameter name. But that, that parentheses-- This one? No. That's defining the function. Oh. And the parameters are going to be passed into it. Whenever you see the keyword function followed by two parentheses, that's not call time. That's part of the function definition. Got it. So the main thing to pay attention to is just the keyword function that's followed by parentheses, then you know that that that's just, that's going to be the parameters. So like function val, that's like kind of in line definition, and? Yeah, so that's just an anonymous function that we're passing to foreach and then val is going to be a parameter to that function. Mm-hmm. Cool.
Arguments and Parameters
I'm just going to jump right in to looping and, well, I'm sorry, that's a misnamed slide. We're going to talk a little about constructors and we're going to be using loops and we're going to build on this more tomorrow when we get into the functional programming so we're going to do some things here, just the manual way, which tomorrow we'll sort of apply some functional approaches using the underscore library. But the first thing I want to talk about is the idea of a function as a constructor. And as we see, we have this function called AnimalMaker on the screen. We have the capital A to let other programmers know that this is a constructor and what a constructor is, at its core, is a function that returns an object, that's it. So we see here we have our AnimalMaker, it's just returning a function, I'm sorry, it's returning an object, and what, what does this object, what properties does this object contain? Speak. Speak. Yeah, so speak and it's a function that just console logs the name of the animal. True? So then if we wanted to, you know, create an animal object, so var my animal, oops, equals, just a second. We had to put our function in there so var my animal equals AnimalMaker and then we could pass it a name. Who has a pet that they love? What's it's name? Cheetah. Cheetah? Cheetah or Cheetoh? Cheetah. Cheetah. Okay, like that? She look like a cheetah. Oh, cool. It's a kitty. Is that how you spell Cheetah? Yeah, okay? So now, we just used our constructor function to create our animal object. And here we are. And then, if we wanted to then, if we then wanted our animal to to speak, how would we go about doing that? Yeah we could use a dot. And then what? Yep, good job. .speak? Like that? And what's this going to return? Function. Or no, there is a return, isn't there? What's going to happen? Don't we have to put the parens in there? Yeah, absolutely. So if we don't put the parentheses, we just get a function. And that's not really what we expected, right? We actually, we want it to do what we expect it to do, which is to console.log my name is name speak and so it says, "My name is Cheetah". Cool. So that's the essence of a constructor function and so we're taking some information and we're turning it into an object that we then ha, and then we have a model of our data that we can use in some way. And notice the rules again, they don't change. The ways that we access our methods are the same when you can use dot notation, or we can also use our bracket notation. Like this guys. Like this? What am I missing? Quotes. Quotes, exactly. There we are. So and then, I was talking with a student the other day about-- So in bra, I'm sorry, in bracket notation you have the invocation also? Yeah. Okay. Absolutely. Okay. That's important. Mm-hmm. So So I was talking with someone the other day about when you inspect when you inspect the inside of a function here, we don't actual, it's not saying Cheetah, it's saying name. And we got into a discussion about why why doesn't it just say Cheetah, if it's going to be Cheetah? And the answer is is that before you call a function, your parameters don't have a value, remember? And so even though we know that it's going to be Cheetah, that that variable gets its value dynamically when you call the function, and so that's something to note when you're, when you're going through your code.
So now it's exercise time. So if we just go back to where we were, sort of like our table of contents, you can just go to the functions exercise and get started. And again, it's the same, it's all in script.js file in your JS bin and you're going to go through and put some functionality in there. So, and we'll have about, 30, let's see, what time is it? Two? Yeah, we'll have about 40 minutes for these is a little bit longer. So let's go with 40 minutes. There's a question in the chapter in here. Oh. So Pete asked, how does AnimalMaker know when it is passed an array, it is passed an array, and has to iterate through it, versus just grabbing the first value? So we're actually explicitly, where are my slides? We're actually explicitly looping through it. So AnimalMaker, the function itself, knows nothing of the array. What we're actually doing is we're just looping and here, actually this slide up here makes it a little more clear. So we're just looping, so this for loop is actually what's doing the looping part. And inside of the for loop, we're actually passing the animalName, we can see it here. This is where we're calling AnimalMaker, and we're not calling AnimalMaker with the entire array. We're actually calling it with one value in the array, so animalNames at i, so the first one, the zero with index, would be sheep, so it's saying AnimalMaker's, and then you could replace that right here, like, with sheep, for example. So that's how I know, so does that answer your questions? Cool.
Functions Exercise Solution
And it's supposed to be a little bit of a difficult challenge. It's really combining all the different things that we've gone over today: functions, arrays, objects, loops, and just really tying everything together. So, let's see, let me find my solutions. Here we go. Is there a solution file somewhere? There is a solution slide. I'll show, I'll tell you how to get to the solutions later. I don't like to give it away ahead of time because yeah, because then you'll cheat and that would be too easy. So the first thing is for questions one and two combined we have this AnimalTestUser. We, for the first one, though, let me just type out the first version. It's just a, so the first one, we could say var AnimalTest equals a function, and this function takes the username as a parameter and then it just returns an object. So you see that, see how I expanded that object? So there's an object there and then I just expand it out and in there I'm going to write some properties. And the property was, I believe, so it was just username and then username. So this is a little bit confusing. So we have username on one side of the colon, and then we have username on the other side of the colon and username is a parameter. Which one actually, is going to be the one that's going to be turned into the username? So if I called this and I said var like myCow equals AnimalTest and then I passed them, what's a good cow name? Like Bessy or something. Elsie. Bessy? Elsie. I don't know how to spell Bessy, but that's as good as it's going to get. So, which one wins? So is the property name Bessy? Or is that value going to be Bessy? Absolutely, so the value in this case is going to be Bessy. Here's the parameter. When we have the property name on the left side of the colon like that, that's going to be assumed as a string in object literal notation and it won't ever be evaluated as an expression. So before I was talking about how we could use bracket notation to put an expression for the property name? We can't do that with object literal notation. So keep that in mind, that this will always be assumed as a string. If it makes you feel better, you can just put it in quotes to remind yourself that, okay this one on the left is a string and the value on the right is the one that's going to be my parameter, which, once I pass, once I pass the string Bessy, then that parameter has the value Bessy. And if we, if we just wanted to, like, console.log myCow, that username, that is going to print out Bessy, right? Thumbs on that? Thumbs on that, how many people finished that one? Awesome, good job guys! So that's step one. And then the second part of the question was if the arguments are, let's see, if the length of the arguments is greater than one, put the other arguments as a property, or as a an array in, as an array, I'm sorry, let me re-word that. As a property with the value of an array of those arguments. Are you guys following? I kind of lost myself in that explanation. So, other args is going to be an array of the arguments passed in, if there's more than one argument. And so there's a few ways you could have done that. So one way you could do it, so here we have args, which is going to be the length of the, I think a better one would be like arg length, just to be, like, a little more clear on what args is. So we say argLength, so that's going to be the length of the args, it's going to be a number, and then we have-- ArgLength in the if statement? No? Oh, thank you. Someone's paying attention, awesome. So if, so if the length is greater than one, then we're going to enter into this if block and the simplest way, I'm using the concepts that we actually covered in the class, it's just a loop through that arguments array and push them, except for the first one. So that's why our i there, our var i, is going to start at one instead of zero and so you loop through and you push each argument into an array and that would create an array. The other one is what I mentioned briefly earlier, the array.prototype.slice.call will also turn it into an array. But, we can stick to this one because it's more straightforward. The other one goes into prototype land, which is not somewhere I really want to go right now. Any questions about this method? I didn't see that slice.call on the documentation, so call is a function of slice, which is a method-- Call is a method on all functions. And if we have time tomorrow, I have some slides that go over call and apply, if we have time. Call and apply. So, fingers cross. Yeah, so call and apply are two function methods that are commonly used and they're really useful for if we're doing, for functional programming, when you're doing some generic things with functions. But we'll see, we'll see if we get there tomorrow. So they're kind of already built in, not-- Yeah. Yeah, exactly. So like how push is a native array method, call and apply are native function methods. Okay. And that goes back to how functions are also objects, they also have methods, et cetera. Cool. Did you have a question? Nah. (laughter) Cool. Sweet. Da da da. Let's see, let's put on word wrap here so we can see everything. So here's a more complicated version of our first animal user. So it takes username, it takes a species, it takes a tagline, it takes noises. So starting to sound familiar from our other exercises. So what we're doing here is we're creating a constructor function for our animal model. And so here we have an object, and we're just storing it in a variable, which you could do. And again, you could just put quotes around this to sort of, so you know which one's which. There you go. And we're just initializing these values and here at the very end, we are returning that object. And another way that you can, you could do this is simply by just returning the object literal instead of the variable name, but they do the exact same thing. There's no, there's no difference there. Any questions on this one? No? Cool. So here's just an example of how you would use it. So we're passing in a series of arguments and then you can console log sheep and you'll see that sheep is going to be hopefully whoops is going to be an object. So here is sheep, our sheep, and we see it has, its name is Cloud, it's a sheep, tagline is "You can count on me!" and it has a noises array of the noises and it has an empty friends array. Whoops, I lost where I was. Questions on that? Cool. So I'm going to try to go through this quick so that we can keep going. So here's our function addFriend. It takes an animal and it takes a friend, which you want to add to the friend, so if you wanted to simply push, if you wanted to push the whole object it would be animal.friends.push and you would push that friend and so that would be the entire object and so at this point, if we looked at it, we could do this, oops, I keep trying to open the console up in Sublime and it's not liking that. Do we have sheep here still? No, okay. So let's do this uh oh. Da da da. Okay. Okay. So we have sheep and now I think we'll just add Cloud's going to be his own friend, so we're going to give sheep a sheep and so now we can see that sheep has itself as a friend. And you can see there. Cool? And then if you wanted to save space, you didn't want to pass around whole objects, you could just, or you didn't want to save whole objects, you can just keep the username there, or their userid or something like that. And do it that way. And in that case it would just save the name. So here's some other ones. Cow, sheep, and llamas. So here's one way that we can just create our farm by just using our array little notation, pass, putting those variables in there that represent our animal objects like that-- So those were already created in the AnimalCreator? Yeah up here, you can kind of see-- Got it. Here's llama, here's cow. And here's how you can add matches so okay let's see. So we're looping through farm, we could actually use, which might be better, is we could just use a regular for loop with semicolons rather than this for in loop, because again, if we had some properties on our array it might do some silly things that we aren't expecting. But you could also do that as well. So we have farm and then inside farm we have animal for each animal in the farm .matches, so the matches is creating a matches property there and initializing it to an empty array, so this function just gives our, each animal in our farm the ability to have a match. Whereas before, they can only have friends. Like maybe you could only have fr, you could only get matches if you're a premium user. So you can only have friends, and then if you want to do the dating matching part, or something, then you can upgrade them and give them matches. Just don't tell them that they could just put this function in their console and they wouldn't have to pay anything. Not business model-ly perfect. So and then here is a function that gives matches and it looks like it is just going to loop through all those animals in the farm and it's going to push the first friend of each animal as a match and you could get fancy with this and like make it a random match or perhaps in future iterations of your data structure you'll have some some ratings based on a test that they take, and then they'll find, in the farm, other animals that have a similar, a close rating to them and then match that way. Mm-hmm? So when this one animal is it like cow, sheep, llama, is that what it's, it's not like going to the username and matching username-- Right. It's-- It's saying sheep to sheep and cow to cow-- Yes, exactly. So it's looping through, and again, this would this would be better as a for loop with semicolons. It will work this way, but in general you're going to want to use those for loop with semicolons when you're looping through an array. I used foreach. Oh yeah, or you can use foreach. We'll talk about that more tomorrow. Cool and this is how you would use giveMatches, you just pass the whole farm to it and then you can check it by just inspecting your farm and seeing if there's animals, other animals, in your matches. I think I said that all without breathing. Any questions? No? I have a question. Sure. Line 75 and line 76. Mm-hmm? So farm on line 75, is an array? Mm-hmm. Same thing. As this. And then that variable animal is some indexer into the array? What is it actually doing on line 76 where it says farm brackets-- So animal is actually going to be a, is going to be the i, so you could maybe it would look better if it was an i. But in general you're going to want to use the for loop with semicolons here, where you say for var i equals, you know, less than array.length. That one would be better. This will work, but since farm is an array and in a lot of NBC's, especially, or at least Backbone, which is the one I use mostly, is that your collection is actually going to be an object. It's not usually an array. It's usually, it's an object that contains an array, so, so that's probably where the solution is kind of basing that on. Cool. All right, so if we don't have any questions on that, we'll just move on to nesting and that's going to be our last topic for today. Can you, can you just speak to the, the assignment, or the exercise file where you have, under each exercise number, you have like a code area and then you have some items commented out. Is that like a hint for what you're trying to do? Let's see. This here? Yeah, so-- Yeah, so that's saying that this console log will print out this. And what about three below that? Yeah, so we're console logging sheep-- Oh, okay. And so sheep should be an object that looks like this one. So that's what the log would print for that? Yeah. So it's just kind of giving you some guidance into what you should be expecting your solution to look like. All right, thanks. Can you go down to that number eight? Mm-hmm. And so that matches Zanny so that, Zanny is a sheep? And that's why sh, and that's why Zanny is in the matches? It really depends on how you implement your matches. Your giveMatches function. We don't, we don't do species discrimination on eFarmony, so, it's usually just the first, the first one. So the solution does the first one, so-- Oh. So actually, in the solution it would be Moo because that would be the first index. And this one, maybe, is always the last one. It just depends on how you implement it. There's no robust-- Oh, so we're like matching one thing to another. We're just saying the first or the last, or whatever-- Yeah. Oh okay. Yeah, so someone from your friends list will be one of your match. Got it, okay. Yeah, yeah. Right on. And if you want to build that out into something like more interesting, you're welcome to do that. Got it. Yeah. Like matching sheep to sheep, or? Yeah.
(music) So we kind of play with this a little bit, but I want to talk more in depth about dealing with nested data structures and how to access them, and how to think about them in a way that makes it easier. You're going to deal a lot with nested data structures, usually in the form of a JSON, which is how you're probably going to get your data from your back-end or your API. And so here's just an example of how we get started. So we start with a box, our box, that we love, that we've learned to love over the day. And in the box we can have an innerBox, and so innerBox is a property in box, that contains a value which is also an object. And so this is a nested object. And the rules are the same here. So we can also use bracket notation if we wanted to, and our result is the same. And then if we wanted to add a property to that innerBox, simply what we'd do is we'd continue the pattern. So first we access box, right, so we access the whole box, right, which would be this whole object. And then we access the property value, right so, box, innerBox is going to evaluate to a value, which is the value at that property, which happens to be an entire object. And then from there, it's accessing the property full, or it's creating the property full, excuse me. And it's assigning it the value true. And that's where we get that value. Does that make sense? Thumbs on that? Sideways. Do you have a question about it? What are we doing? We're nesting what? We're putting an object inside of our object. But why, why? Why? Just like, you're going to be dealing with nested data structures a lot, and you're going to be creating them, moving them around, getting data out of them, organizing that data in a way that's meaningful for your application. Is it similar to having an array of objects? Yeah, so you can have an array of objects, you can have an object with an array that contains more objects, and you're going to find that you're going to have these super-nested data structures that you're going to get from your API, and then you're going to have to turn that into DOM, and make it a user interface. But first you need to learn how to deal with a nested data structure before you could even get there. Is there a lot of the more complex, let's say, nested structures, is there any way to, because you'll see a wall of text, that's your JSON. Is there a way to run something that see what that structure is, you know, without the values in it? Typically it's a bunch of these, or is that-- Right, so if you're getting it from an API, hopefully documentation might have some information on that. If you have an in point API where you're receiving the data, you can actually just directly go to that URL, and it will print out the data for you directly, and then there's Chrome extensions that sort of prettify it to make it indented and stuff. I guess sort of prettified would work, I guess, put it into a tree-like structure. Yeah, so you can look at it. OK. Yeah. Great question, though. Cool. So in again, and again, the rules don't change. You're going to also use dot notation right after using bracket notation. Still the same. So what is this going to be? What is this going to look like? box.innerBox? Squiggly line, full, full, and true? Everyone agree? Thumbs on the answer? Feel like it's been a long day, we're starting to fall asleep. We're almost there, almost there! So close, awesome. So what if we assign box.innerBox to a variable? What does this look like? Same thing? Yeah, absolutely, it's going to be the same. Oops. Full, true. So... what about here, what if we triply-nest our object and now we have a box, we have an innerBox, and then we have the babyBox. We have a little box family. So and then we're just going to console.log this line here. What is that going to... look like? What is it going to look like? Empty object? Yeah. It's just going to be an empty object. But it wouldn't have, like, three squigglies on the left, and three squigglies on the right? No, it's just one object. It's just one? OK, got it. Because the way to think about it again is we first accessed box, right, which is this whole object. And then we say box.innerBox, right, which is, here's innerBox, so the value stored there is this one. And then we say babyBox. And so the value stored at babyBox is this object. This is before we add the property, so it would be empty at that point. So it would be an empty object. And then, if we do it afterwards, Whoops. What is it going to look like now? What's up? Yup. Oops, kind of. Oh. Cool. So the interesting thing about, I'm going to delete this last line. So the interesting thing also about objects is that if we say var bb it's going to be babyBox, equals that. So here we're going to assign this empty object to the variable bb. Then when we add a property to our babyBox, and we check bb, Oh, every time I do a question mark, it does that. What What is that going to log there? It's OK if you're wrong. Blank? Empty string. Empty string? Empty paren, really. Good guess, and that would be true. That would be true, it would be an empty object, if it was a string. So if we did this. And it was a string, and it wasn't actually an object, it wouldn't, um. It wouldn't change. However, because of something we call being passed around by a reference, bb now is going to actually be referencing the same object. So if you add, uh-oh, whoa. So if you add properties to this object, it's going to show up later. And this is true for objects that raise n-funcs, this is not true for primitive values, like numbers, Boolean values, strings, null undefined, things like that, just objects that raise n-functions, anything that's an object. And so that's something to keep in mind when things start to change a little weird, and you're not... Things start to change when you're not expecting it to, and it's an object, you might want to check on this.
More Nesting Examples
So here we have an example of our innerBox, so we just have a doubly-nested object, we can handle this, right? It's only two. And with property full equals true, what's going to happen in this next line here? How about Ben, what do you think? For what, what's the question? What's the line going to do? Set the property of height of the object's innerBox to 10. Good guess. Anyone think something different? Undefined because innerBox doesn't have a quality on it? Yes, good, good catch. Seeing if you guys are awake. There's coffee in the back. (laughter) OK, awesome, so we fixed that. Cool, that we'll pass. What about the last line there? That's not going to work. And so, what my mission, or my request to you is make that last line work, without changing the last line itself, and we want innerBox2 is going to be a different object. So what, there's a few things you're going to need to do to make that last line work. You can do it here, above it, so that that won't throw an error. So I'll give you guys about five minutes to do it. (throat clears) And also note, innerBox2 is a new, is a different object, it's not the same as innerBox. Did you have a question? Did you mean to leave the mouse closed? Yes. So you can't, you can't change this line, will not be changed. Do you want innerBox to be another box? Yeah. Another, like a sibling of innerBox? Yes, exactly. So it'll be another object. So you need to create a new object in there. Cool, so, our online friend Sancar, sorry if I pronounce your name wrong, answered this, so I'll just go ahead, type out the answer. So, to do this, we first need to, to create a variable, right, called innerBox2. We know that because innerBox2 doesn't have quotes. And we can like, call it something else, even. So we can call it otherBox. And then we have to, on box, put a property called otherBox, and set it equal to an empty object. So we need to do this first so that we have an empty object, on box, to add the full property to. So now we say box, which is our object, and then we say, oh look, that's a variable, what, what does that value hold? Oh, it's otherBox, so you can imagine then, that this is swapped out, so that would say like, box dot, or box.otherBox, which we know is an empty object. Here. And then we'll just put a nested property on there, I'm sorry we'll just put a property onto that object, set it equal to false. And that's the answer. Whoops. Any questions on how we got from from just the empty object, from the variable to the empty object? Couldn't you just assign innerBox2 to box? So, point to box itself? Well then, then it would say, then it would be kinda like saying this. Which wouldn't make sense, because we don't have, and you really don't, that's called circular pointing. And that's like, something you don't want to do. But, Yeah, you can't really do that. Because we don't have a property called box on box, right? So you could create it I guess, but. So Kate asked, when do you know to set a variable to an empty object? Do you always have to do that, is it a best practice thing? Well if you're creating an object, Can you repeat the question? Sure, the question is, when do you know to set a variable to an empty object, and do you always have to do that? And is it a best practice thing? So whenever you create an object from scratch, that's what you have to do. There is constructory notation with the keyword new, and then capital O Object, but, that's not a best practice, in general, and so it's better just to initialize your empty object using the curly brackets. So what this does it that it just creates an empty object, so that you can add properties to it.
So this is going to be our last exercise. It's one of the longer ones, so. Let's see, we go back home. Yeah, it's just called nested. Nested data. And, oh I guess it's not as long as I thought it was.
Nesting Exercise Solution
Local and Global Scope
Parent vs. Child Scope
So we're talking about how to make privacy with or make local variables in our locals-- in our functions but what if we have a function nested inside of another function, how does that affect our scope? What do we need to know about that to effectively handle our functions? So, we have here just a review is we have this blender function in here. See, this is a name function. This is the one that's being stored in a var. So we have a blender function, it takes fruit and it assigns that fruit to b, and then it blends smoothie, bs means blend smoothie. And it's going to alert the fruit, whatever you pass into it plus yogurt makes a fruit swirl. And then we call it here and then we call it down here. And the question is, what if we, like where can we access these variables in this nested scope? So the parent that has no access to the child scope, so if we said var, I don't know, x equals astf. Sorry. My creative juices are a little, are a little slow this morning. We couldn't say down here. We couldn't console dot log x. That's because while child scopes are nested, the inner nested function has access to the parent scope as well as the global scope where the parent don't have access to the child scope. And at Hack Reactor we use this metaphor for functions that I mentioned yesterday where a function is like a blender, a blender is an object. We can move it around, I can hand it to different people and we can say that in a variable if we wanted to. But to run the function or to turn on the blender, you have to put in the fruit and then press the button, right? And so, call time is pressing the button for example and when... And so, the extension of that metaphor as it applies to scope, it's a little gruesome but you never want to put your hand inside the blender. So if you kind of forget which way, who can access what, if it's the parent or the child, just remember you can't put your hand inside of a blender or you don't want to put your hand inside of a blender. And that will help you remember that the parent can't reach into the child scope but the child can actually reach into the parent scope. So that's why here in this alert we can access the variables in the parent scope here y and b but we can't console dot log x down here at the bottom. Mm-hmm? I guess I'm confused with the analogy. How can the, why would you want a child reaching into a blender? (laughs) You don't want children reaching into blenders. It's not what I'm trying to promote. You don't, so this... So we have a nested function here, you see that we have this blend smoothie function and then we have the blender function, right? So we have this function inside of the function and the question is which scope? So we have two different scopes that we're talking about. We have the parent scope and then we have the child scope, and we're trying to figure out which scopes have access to which variables? So the child one, the inner function has access to the parent scope and the global scope and all the way up the chain. So if it was nested many times, any parent, it has access to those variables in that scope. However, the parent cannot access the child scope so this outer scope here can't access this inner scope. And that's why this console dot log x would throw an error. That makes sense? Cool. Somebody, I was just asking I think of why you were calling the bs function rather than returning? Rather than returning it? Yeah. Just because we're just calling it, I mean there's no reason. We could return it but that adds an extra step of having to call it later. We're not returning anything from this function at all, we're just alerting, so we could play with this function if we wanted to. So, I don't know if you can read that but it says blueberry and yogurt makes a blueberry swirl. And so, we just created the scope here. So when we called this blender function we created this scope that you can kind of represent by these brackets. We created a scope there. And then here, I'm sorry, and then here when we called this blender, blend smoothie function, bs is like a terrible naming. I didn't think about that ahead of time. When we call the blend smoothing function, we create a second scope here. So this inner scope has access to the parent scope and that's why b and y, they know what values they hold because the child scope acts as the parent. If you move the bs invocation down two lines will that work? No. And the reason, so the question was if we move this, this bs call time down here, would it work? And the answer is no because the function bs is actually local to the blender function and so just like we couldn't console dot log local up here because it's private, we can't console log. We can't access the bs here. So and the other thing is there's no arguments being passed to bs but it's still rendering the blueberry and the yogurt because they're-- Because it has access to the parent scope. Has access to the parent scope. Mm-hmm. A follow up on the moving the invocation. If you move it down two lines could you say blender dot bs? No. No, you couldn't. But if you named it that way wouldn't it hoist it up? It would hoist it to the top of the scope. So it would be, you can-- Okay. It would be like equivalent to just like... So how the hoisting would work is it would be an equivalent of just like putting it up at the very top. So we could technically, oops. We could technically call it up here. This is like not something I want to cover too in depth because it's a little bit confusing. But the way that this function works it's hoisted so that you could actually call the function up here. Yup? Question about the variable x. If it was declared with the var keyword would it be in the global scope or just the scope above it? Good question. So if we do it like that and we take off the var then that would be in the global scope. So it would be the equivalent of being in the scope up here.
Scope Exercise Solution
(music) Anyone think about any questions, some scope questions during the break? Yeah. So when you have nested scopes, is that same thing as, I looked it up a little bit, is that the same thing as lexical scope? When you have nested scopes? So, lexical scope basically means that if you look at it, the scope is defined by how it looks, like so if the nested scope is inside of it, it's yeah, so I guess you could think of it that way, like nested scope is an example of lexical scope. Yeah. So if you have the function sibling and even though you're calling it from inside, that scope doesn't work because of something called lexical scope. And the way I think about it is that if you see the function actually inside, then it has access. It's not like an academic definition, that's just like my working understanding of how that is. Cool, and Joe, you said you had a question? You answered it, awesome. Cool, anyone else have any questions? All right. So we're gonna talk about closure. So closure is the next step with scope. A closure happens when you return a function from inside of the function, and that inner function retains access to the scope. We saw that a little bit in our exercises here at the very bottom. So even though we made this inner function global, it still had access, and it remembered, quote unquote, that we had incremented our counter inner scope to 12. And so-- Why? Why? We're gonna get there. We're gonna get there. We'll walk through it. And so that is an example of closure. Isn't it a violation of scope, though? It's a violation of scope. No, I think it's taking advantage of the power of scope to do some interesting things. Didn't we say that the variable inside the function is not available to something that's outside the function? But if you return a function from inside the function, that function was originally inside the function. But we'll get there, we'll walk through it. We'll walk through it step-by-step, and talk about what I mean when I say closure. So our first thing I want us to look at is a function called closureAlert. And it says, so function that has a variable that's initialized that says, "Help, I'm a variable "stuck in a closure!" And then we have this inner function called alerter, and all it does is alert X, and then we call alerter from inside. So let's play with this in our console. Can everyone see that? Even in the back? Cool. Thanks. So now, so we have closureAlert. So if I just type out closureAlert, what does that, what's gonna do, what's gonna happen? How about Ben? What's gonna happen if I just type out closureAlert like that? It's gonna return the definition of the function. Absolutely. So it's just gonna return the definition of the function. And then if we wanna call the function, we put the two parentheses. All right? So we call it. Once we call it, it's gonna go into this function body, right? It's gonna declare this variable, it's gonna say, great there's a function, then it's gonna call alerter, and then that point it goes inside alerter's function body, and alerts X. And then we have this alert. Can someone read that? "Help, I'm a variable stuck in a closure." Thank you. Awesome. So that seems comfortable. We've done that before, right? In previous exercises. We're just calling a function from inside of a function. And it's not a surprise to us that this X refers to the X in the parent function, because we know that their child function retains access to that parent. Cool? Any questions on that? Thumbs? Cool. Did you have a question, with the side thumb? No, I'm good. I didn't see where you called the closureAlert, so that never did call it at all then? Well, I just called it in the console, but for example, you could just do like this. Yeah.
Closure Introduction, Continued
Creating a Closure
So here is the same thing, except, hold on, I like it when it says "I'm stuck in a closure." Let's put that there. Oh, I see, that's why I changed it. Never mind, I can't do it. Darn. So here we have our closureAlert. The one thing that we did change here is we changed X to zero, because we're gonna be changing it when we alert, and the other thing that we changed is instead of calling it inside of here, we're just returning it. This is really similar from our scope exercises as well, right? So we return alerter, which means that when we call closureAlert, we enter into the function body, right? First thing it does is it initializes X at zero. It sees that we have, oops, it sees that we have this alerter function, skips over it, and then returns it. And so our funcStorer is storing alerter. And let's just put that in the console so we can, we can look at it. So if we just type out funcStorer here, we see that it's just that function, right? And the same with funcStorer2, again. And what it's doing is incrementing X and then returning X. That's what plus plus X means. So you add one to X, then you return it. Whereas X plus plus is you return and then you add. So it doesn't show up as well. So if we wanted to then call alerter, how would we go about doing that? funcStorer and then vacation? Yeah, so we just have funcStorer, and then we call it just like that. What's it gonna alert? One. Yep. And then if we call it again? Two. Why is it two? It remembers the scope that it was in. Mhm. And so this is our closure. Which is a fancy word. Just forget the word for now, but for those of you who are wondering, that's the closure, and I'll talk about it a little bit more. So in funcStorer, we call it, it's holding reference to this alerter function, so you can kind of imagine that when we call it, it goes into this function body, it increments X, then returns it as an alert, and so X is then one. If we call it again, and I see you, I'll call you in a second. Call it again. So this is one. It's gonna go back inside alerter, and it's gonna increment again, and alert it, and it's gonna alert two. Is that because we're really kind of storing it, we're not calling closureAlert, we're storing it? Sort of reference it? Yeah, yeah, so we're storing it in a variable so that we can access it later an call it later, and that function, because of lexical scope, has access to its parent scope still. So in a way, it remembers the environment. Actually, you are calling the closureAlert, but the closureAlert is returning a function that's got a defined determiner? Mhm. But you haven't executed that internal function yet. So the difference would be, if we, on the console, just invoke closureAlert twice you just get one every time you do closureAlert. 'Cause you're not storing it. You would get a new copy of the alerter function as the return value. Mhm. So, if we did funcStorer2, that's still gonna alert one, because every time we call a function, it creates a brand-new scope. And did you have a question, Mark? They just wanted you to cover a pre-increment versus post-increment. Mhm. And then the other question was, is returnAlerter the same as calling and opening alerter? Okay. So as far as the incrementer. Here, plus plus X what that does is it adds one to X and then returns it. Versus X plus plus, it returns X first and then increments it, but that's not important. By returns, you mean make available to the alert function. Yes, yes. So if we changed it, and it would first, if we did this it would stay zero, and it just isn't very good for my example. So. And then, the second question is, is returning alerter the same as invoking it and returning it? And the question is absolutely not. Because if we're invoking it here, then we can't call it down here. What we're doing when we don't invoke it is that we're just returning the function definition itself. So if instead of returning it, if we, right here we can console log it here, console.log, alerter, and this will show us what we're gonna return. We'll put this in the console and kind of look at it. So again, we're just console logging Alerter, and then it's gonna be returned. And so we know that whatever this function returns is then gonna be stored in this variable. Oh yeah, and then there's our console log. There's our console log there, and then we can also look at funcStorer, and we see that it's the same thing. And since it's a function now, we can call it. If it wasn't a function, we couldn't call it. So for example, if we just returned alerter and called it already, it's gonna return whatever this function is returning. So in this case, it's not returning anything, but if we wanted to put a return there just for the example, we can return true, so the change here is inside the alerter function and returning true, and then instead of just returning the function definition, I'm returning and invoking the function. So it's gonna invoke the function and return whatever that function invokes. Cool. Woops. So... So and then if we look at funcStorer now, it's undefined. Oh, that's weird. Oh, I changed it. So I guess I erased that return true. So it's undefined because this function is returning undefined. But if we return true, return true, and then did it. And we looked at funcStorer, and now holds the value true, and you can't, true is not a function. True is a value, so you couldn't call true, that doesn't make sense. So that's why we want funcStorer to be a function and not the result of the function. So that we have like this little window into that parent scope that we can access later, and it can be very powerful. And now, since funcStorer is a function, we can go ahead and call it. And we can call it again, and this is our counter. We can count.
Closures and Functional Programming
So here is an example of how we could use closure. So maybe we have this add function, and we want it to just make a generic add function, called like add5 = add 5. And now we have this add5 function that we can call later with another number, let's do a smaller number, and that would give us seven. Now let's walk through exactly how this is working. Let's play the game. Where did we leave off for our game? Did we leave off, Grace you went, Joe went, I think it was your turn. Let's walk through how this is running the browser. Well, you said the function add has a variable. Mhm. You skip down-- To the bottom? Cool. Perfect. Kim? Variable add five is add. So we call the add function, and then, who's up back there? William? So you call that function that the variable add is pointing to, so the value of five goes into the num. Mhm, so when we get into the function body num is now five. And then, Andy? Then we're creating a local variable called num1, setting it to the parameter five. Mhm. Kevin. And then new function, add two to that one. Mhm. And then you return that function without running it? Yeah. So we skip over the function body here, this never is run, then we just return, add to num1, and then Jake? Then it's complete. Almost. So return it, where does it return to? Add five. Yeah. So now var add five is whatever that function returns, which add to num1, right? So now this is a function, and then, Tanner? Then we're passing five, or wait. Passing five into the number? Well we just did that one, so we skip past that. Okay, an then we add two to five. Mhm. So we're calling the add5 function. Twice. With the argument two. Okay. Now, we only called it once. We called it here. This is a different one, this is add, now this one's add5. add5, remember, is gonna be this function here, 'cause that's what we returned. Okay. And then we pass it two. And then where does it go, Phil? Well, because add5 contains the contents, it also contains the variable num one (mumbles) scope. Mhm. Because it's five-- Mhm, so we hop right back up here, right? But you turn statement that it is, I mean two five? Yep, exactly. So we call add5 with two, we jump up here to the function body, num2 is now two, and then we add num1 plus num2. num1, again we got from the first time that we called add, right so num1 equals num, we got five from here, and because of closure, we have access to the environment here. The previous environment. The previous environment, yes. And that's how we got seven. So if you get add5 (mumbles) Right? Well, actually, we add five and do three, it's gonna be eight. Why? Beause the add parentheses five is retained. Mhm. As num1 equals five. Mhm. Because, even though we have reference to this scope here, every time we call add5, we're creating a new scope here. So num2 is gonna change. And we're not actually affecting num1. So num1 is being saved, num1 is always gonna be five in add5, but num2 is gonna be the one that changes. So when we pass two here, num2 is then two, and when we pass three at that point we make a new scope, this new scope here. But just because we have a new scope for the add to num1 function, that doesn't mean the parent scope is different, it's still the same. And the num2 would be three, which would be eight. So what if we didn't have that add to num function? Let's just assume that the whole function definition of add to num1 is gone. Mhm? I mean, I guess that defeats the purpose of having closure, but. Mhm. But you could still, so then that's just, then when you assign add parentheses five to add5, it's like-- It would call this whole thing over again. Yeah. And it would reset this variable. Right. So it would just be like a regular storing of function into variable, like your plain vanilla? Yep. Got it. Yeah. So the key here is that for the closures that we have a function in here, and then we're returning it so that we can call it later. Right. And then using the parent variable for permanence or-- Yeah. And actually, we don't need this here. This is just for clarification. Like, you could actually delete this and call this num. It would actually still work. So, just for fun, if you had, after that last statement, if you had add parentheses 10, and then you, I'm sorry could you add-- Here? No, at the very bottom. Mhm? If you said add5 equals add parentheses 10... add5 equals add 10? Yes. Mhm. And then you said add5 parenthesis two, what would you do? So this would be rewriting add5. So add5 was add parentheses five, right? Which is gonna be this function. This would overwrite, woah. This would overwrite it and make it 10. Okay. Doesn't like it when I click there. So if we did add5 two, then that would be 12. 'Cause we're just, whenever we use an assignment like this it's gonna completely override and just delete-- Whatever was there. Whatever was there, yeah. 'Cause f5 keeping that same reference in memory. No, it will overwrite that. Overwrite that, yeah. It will overwrite everything. But it would be better if we could just call that add10, right? But if we did want to do that, it would still be the same.
So the other cool thing is that this also works if we're returning an object with methods. So the same rules apply, beause see look. We have these functions that are still inside this parent scope, even though we're actually returning it in an object. So let's explore what that looks like. Well, I'll type it out here, and I'll paste it. So we're gonna call... So here's like a counter, we're gonna call counter. Okay. So where did we leave off? Actually, I think, Phil, you were the last one, right last time? So we should start at the beginning. I guess that'll be you, Rich. Okay, so... It's like a global function, I guess, called counter. Mhm. It's basically initializes and then it finds that and then it goes down to the, skips the whole bottom So we said great, there's a counter, we skip it, and then Grace. We assigned myCounter, the return value of counter function. Sure, so we called counter and then it goes to the counter body, and then Joe? Sets the local variable N to zero. Mhm. Then myCounter is equal to the return value. Mhm. So you return that. What is this? The object of two functions. Yeah, so this is an object literal, it has two properties on it, one is count and one is reset, and they're both functions. So you can call it a method. It might not look like an object in this form, but if we delete this, you can see that there's just an object with our properties in there. So we're returning an object, great. So what is myCounter now, Kim? Object count colon the function. Mhm, totally. And then if we wanted to increment the counter, how would we do that, William? Knowing that myCounter is an object. Actually, let's inspect it before we jump ahead. So we have myCounter is an object with two properties. So if we wanted to count, we wanted our counter to count, how do we access the counter property? Dot? Yeah, we could use dot. Dot what? Dot count. Dot count, like this? Up? So if we don't call it right, it's just gonna be the name, so we need to invoke our function, and it's gonna increment it. So there's one, and then we can keep doing it, right, it's just gonna keep counting. So we can see myCounter, still just an object, we haven't affected anything, and then if we wanted to reset it, could we do this? Yep, that will also work. We can use bracket notation. And so... Count like that. So as we see, we can return the functions from inside of an object as well. And this N is still holding access to its parent scope in its previous environment. So if we wanted to call it again, oops. That's myCounter.count, and we have to call that since it's a function. It's gonna be one. That's gonna be two, et cetera. Cool? Thumbs? The only difference between this and the previous example is that we're using the dot notation to access the function in the object. Yeah. That's being returned from the-- Right. so the main difference is that for this one we're just returning one function, and in the next one we're returning an object that contains two functions. So if you wanted to have to do different things like reset the counter, you're gonna need two different functions, right? So this is how you would do that.
Closure Exercise Solution
So the first one was write a function called nonsense that takes an input string, this function contains another function, blab, which alerts that string and is immediately in call, is immediately called inside the function nonsense. And here's an example of what blab should look like, just a function, it alerts string, and so we have our function, nonsense, here, I called the parameter string, and then if we were gonna call nonsense we could say nonsense, and we can, oh actually I already did it down there. So we can call nonsense down here with blah blah blah, so the string is now this blah blah blah, and then we enter through the function body here. We see that there's another function, we skip it, we call blab, and blab then alerts what? Yep, blah blah blah, exactly. So for the second one, we're doing something a little bit different. Instead of immediately calling blab, we're calling it after two seconds, so we're settimeout, and then it will still alert blab. So, for the third one instead of calling it inside or doing a settimeout, we're just gonna return the function body. So we see here on line 34, we return blab, which is gonna return the function body. So blab later is actually gonna be the function body here and it's gonna alert when we call it. So if we call blab later here it's going to what? What is it going to alert? Kevin, do you know? (whispering) Blah blah blah. Yeah, exactly. So it's gonna alert blah blah blah. (whispering) And the blab again later. We called it. What's that gonna return? Tanner? It's gonna return blah blah blah? Close. It's actually gonna return hee hee hee. Because we called nonsense with hee hee hee, so string in this case is gonna be hee hee hee. Can you guys see that in the back? Cool? What if we did blab later here? What's gonna alert? John. Could you repeat the question, please? Sure, oh I'm sorry I didn't realize you were on your phone. If we called blab again later in here, what is that gonna return? What is this gonna alert? Blah blah blah. Yep, so it's still gonna alert blah blah blah, so the fact that blab again later is alerting hee hee hee doesn't affect the blah blah blah. If that makes any sense. (laughs) And why is that? Why are they two separate things? Grace, do you remember? Oh, Tanner remembers. Why, Tanner. I just want redemption because you're passing me the variables, so after nonsense. Yeah, absolutely. And every time we call that function, the inner function's creating a new scope. Even though they both are sharing the same parent scope, it's new. It's a new inner scope here for this function. Cool. Dun dun dun. So this is a function called lastNameTrier, you pass it your first name and it creates this complicated algorithm that can, you can try on last names. Like little girls do when they have a crush, you know. If you have lots of crushes you can see which one sounds better with your name. So how it works is you pass in your first name, so if your first name is Farmer you would pass Farmer, and then you could try on the last name Brown, that's gonna log Farmer Brown. And it's also really convenient if like you really, really like someone and you wanna just write their name all over everything, you can just like do this a bunch of times. You know? I don't think boys do this, but girls they write their crushes' names a lot. No? No, no one? Okay. Just me, all right ,fine. Do you use gel pens? What? Yeah, with gel pens, absolutely. you gotta be careful 'cause they smear, you know? There's an art to it. Okay, anyway, too much information. So here if you wanna try on different farmer names, so Farmer Jane, Farmer Lynn, for example. That's for the farmer to find out if he's gonna marry the Jane or the Lynn. Yeah. So guys could use this function. Yeah, absolutely. It's a gender-neutral. Or it could be a female farmer, too. Yeah, mhm. Marry a farmer. Or if you're giving birth and you know that your prodigy is gonna be a farmer, you can match that, so you know, it's-- It's very unisex, yeah. Yeah. Cool. Anyway. So here we have our function, so our parent function is here, and then we have an inner function here. And again we're returning that inner. So how we'd run this is, we'd say, oh and I forgot to mention, Katrina is our, these are Katrina's solutions. So she's awesome. Look her up, add her on Twitter, all those things. So Katrina, so var first name Katrina, pass the string Katrina and then to lastNameTrier, so the string Katrina is now a first name, we have this inner function, we skip it, and we return in. so first name Katrina now is the value of this inner function. So now when we call first name Katrina we can pass her last name, which I'm not gonna try to pronounce, Wychaco, I guess I tried it. So Wychaco is last name, and then we're just going to console.log the first name plus the last name. The cool thing here is that this parameter stays the same, Katrina, we don't actually have to say var first name like this, oops, equals first name or anything like that, it just holds reference to the parameters, 'cause it also live in the scope. So we can just do it like that, and then you can also you know, try it with Smith as well. Any questions on that? So it's like, you can do like Fibonacci series with these because they're storing the results of the next... Yeah. Yeah, you can do, you can do a lot of different things with it. I think there's one thing, oh there's one thing I wanted to mention for this nonsense function, a common mistake that I see is that when you are writing the inner function, you will also give it a parameter name of the same name from the parent function, and that's not gonna work because if you don't pass anything to blab, so when we're calling blab here with no arguments, that means string is now undefined, and the most local, the most local variable value is the one that wins. So this alert here is gonna then alert undefined because it's being overwritten by this parameter name. So if you're seeing that problem, just double-check your inner functions parameter and make sure that that function is actually taking an argument. if it's not, then it's gonna be undefined. Cool. so we have lastNameTrier and then we have this storyWriter. So this is a function that returns an object with two methods. One method is addWords, which will add words to your function, and the other one is erase. So you might imagine that this is like that game that people play where you start off with a story, you start off with like the beginning of a sentence, then the next person adds a sentence, and then you go on and on. You create a big story. Has anyone played that like on road trips before? Not in Minnesota, okay some of you have, okay. So we have, just an example of how we'd use it, we have this variable, farmLoveStory, and we have storyWriter, which is function that we call, and then farmLoveStory is now gonna be an object that has a property addWords, which you can then pass a string. And so the string was, "There was once a lonely cow." And that will just return "There was once a lonely cow," and then you can add more words, and it will concatenate that string and say "There was once a lonely cow "that saw a friendly face," because we just added this there and then another example would be like storyOfMyLife, which is "My code broke" and then "I ate some ice cream." It's pretty consistent in my day-to-day. And then you can erase it. So that's how you would implement. That would be the functionality of the storyWriter function. And so this is what it looks like on the inside. So in a closure scope we have our story, which just starts off empty, right? And then we return this object, and this object has two properties, the first one's addWords, which is a method, and this method takes a string, and story is you add the string, and then I put a space in between, and then I return the story.trim, and then what that does is it just it doesn't show, it deletes the last, the trailing space, so that it wouldn't look, so it doesn't print like "I ate some ice cream" and then space. It doesn't actually trim off, it just shows a copy of the string without the last space, so the space actually still exists in story. And the other, and the erase function's pretty simple, you just set story back to an empty string. Cool? Any questions about that? I wasn't getting, so when you run that, where do you see that on the, that'll actually print that out on the console? 'Cause I'm-- Yeah, that's a good-- Wasn't get defined, you know? In the console? Well, not in the console, in the... What do you mean? Like this one? It builds it correctly but it doesn't operate to the console like your examples show us it should. Mm. Are you returning? Are you saying my example isn't? No, mine isn't. Okay, make sure that you're returning. Mine'll trim, but I just return (mumbles) Mine doesn't either. Since it's not being executed from the console it's not gonna dump it all here unless you actually have a console log statement? To execute the call from a console statement. Mm. 'Cause if it has the return value, then it would show it. Right. So refreshing the page it doesn't necessarily-- Are you doing it in JS Bin? I was not. None of us were using the strings JS file from yesterday. Okay. Yeah, you can just run it directly in your console, like this and it should print out. It's doing it now. Cool.
Higher-order Functions & Callbacks
So now we're going to talk about higher-order functions and callbacks. So what is a higher-order function? So a higher-order function either takes a function as an argument, or it returns a function as an output. So, we've done a lot of returning functions when we were going through closures. Now we're going to talk about how functions take functions. And how to master that. So then we can, once we get to deep diving into our functional programming stuff, we will like have those concepts mastered, and they won't be confusing hopefully. So here's an example of a function taking a function as an argument. So this is adding a click event. And then the callback would be this function here. So a callback is a function as an argument. And then here this looks familiar to us, because we've just been doing it. And this is returning a function from inside a function. Cool. So, callbacks. So here's an example of an ifElse statement abstracted into a function. And so in functional programming, we're using functions rather than procedures I guess. Or we're using we're using functions as units of abstraction. Versus abstracting over data, in functional programming. And so, some silly example is you could just use an ifElse function, instead of an actual ifElse statement. And so here's an example of that. Where we are passing a condition. And then we're passing a callback function for the true condition. And then we're passing a another callback for the isFalse condition. So, here for our example, we are just passing true. So the condition is true and it's going to call, or it's going to enter into this block. And so what's going to happen when this code runs? Console log true? It's going to print out the function? The content of the function. All very good guesses. So what's actually going to happen is it's going to return undefined. So we're not returning. We're not returning these things. And we're not calling them. Oops. So it's important to note that when you are doing this you need to call it. And so when we call a function that's a parameter or that's an argument, it's just like referencing it as a variable. So, if we wanted to call isFalse, we just add the invocation operator, also known as two parentheses, next to that function name. And so this is, these are two anonymous functions that we're passing in. But we could also pass in other variable names. So if we have this function stored at logTrue, we could pass it than as logTrue or logFalse. And that would work just the same. IsTrue would still be, would then be logTrue, would be this function. And isFalse would then be logFalse. And so if we we did this, what would happen? What's going to happen? Kim do you know? What is it? Log false? Yep, it's just going to log false. Exactly. You go to the previous slide. If so, now, silly question. You can't put the invocations in the in the parameter. No, so. That's just bad syntax, or whatever. Yeah, it would just give you an error. So, the thing about parameters, they're just like uninitialized variables until you pass an argument. So just like a variable, you couldn't call. Like, if we just had like var x here, you know it's just an uninitialized variable, you can't call x, because x is just undefined. And so it wouldn't make sense. Like we're just here declaring declaring them as like undefined. Just saying like if there is an argument passed, in this place, it's going to hold a value. If not, it's going to be undefined. Hmhm. There's a question on the chat room. Can you walk through this step by step. They're stuck on the ifElse function and how it works. Oh, yeah, sure. So here, let's do it in the next slide. So, how our browser would read this. It would say, okay, great, we're creating a space in memory called ifElse. We're going to store a function there. This function just happens to have three parameters by these names. Which at this point, they have no value, right. Then we say logTrue is another function. LogFalse is another function. So then we pass to our ifElse false, logTrue and logFalse. So once we call the function, we're going to enter into the function body. And at this point is when our parameters get their values. So, condition is going to be false. IsTrue is going to be logTrue. IsFalse is then logFalse. So we go into the function body now and it says if condition, and so what happens when you put a variable or a an expression in between these two parentheses, it's going to force it into a true or false value, into a boolean value. And so, luckily, ours is already a boolean value. So condition is false. So if it's false, it's not going to enter into this block. It will enter into the else block. However, if this was true, so if we changed this down here to true. So, if condition, so this is the same as saying if condition is true if the value at condition, stored in condition, is true, enter into this part. And then, since we're in this part of the block, this if block, it's going to call isTrue. Otherwise, if it's false, it's going to do the else. And then once it calls isTrue, it just skips to the bottom here. And then basically, you can just imagine, it says return undefined. So, if it's true, it goes here, and then it skips down there. Which means that this else block is never entered if this condition is true. If this condition is false then this is never run. So and then you can read this function as like like if true, do this, else do this.
So we passed in callbacks. We called them, like but what if we want to add an argument? So here's an example of us passing arguments to our function. So we have a couple math functions here. One is called increment. One is called square. So increment just adds one. Square is going to multiply itself, it's going to multiply a number by itself. And here's our function called doMathSoIDontHaveTo. And what it does is it takes a number, and then it takes a function. And what it does is it applies, it calls that function. With that number. And so we implement this by just passing it five, so that's in, and then square, which is the function up here. We enter into the function body. And it's just going to return it's going to return square with five, which is what? Ooo. What is this? This is a math test. Twenty-five. And what about this one. Five. Five. So this is just an example of, we just call the function as if it's just stored in a variable name. There's no difference here. So how would we pass an argument here, to either isTrue or isFalse? What would have to change? To pass a argument? Put it in the function within the if block? Uh-huh. The first thing we'd have to do like this, right? Assuming that we're getting our argument as being passed in from the parent function, we'd have to put it here. And then ya, we'd just pass it just like this. Or we could just say, even like this. We could say var arg equals zero. Or something, and then we can just have our arg inside the function. And we could do it like that. Either way. And then how would we, how would we call this function? Pull ifElse. And then put your condition, your true isFalse, and then your arguments. Mmhmm. And this would be a function. This would be a function. And then pass a number, or whatever. Maybe a string. Cool. Now. Sorry. Mmhmm. Because when we first did some of, when you did the a plus b plus c yesterday and it was a return a plus b. Because it didn't care if you had three arguments. Mmhmm. Even if you don't specify it there in the function definition, the arg, it's just. So, if you don't have that arg up top there in the function definition, and but you ran ifElse, and you had that asdf at the end, it's just going to like, not going to do anything with that. It's just seemed like the c. Exactly. Exactly. Can you explain why we have to define the arg variable? Like why couldn't we just when we actually called it as true function, just pass in the parameter at the time of calling it. Mmm. Because, like here you mean? So if we had this function here. Like here? Right. And then when you Go through the asdf in the-- Exactly. parentheses, in function indications. Mmm. Okay. Because this here, this is just a function definition. We're not invoking the function here. So the only way that we can give a parameter a value or pass an argument is when you're actually calling the function. So, we're actually calling the function at this line. We're not calling the function here. We're just passing the definition. So, if we were to call the function, you have to have the two parentheses. So how does the, like if you have a click event, in JQuery, I'm just thinking. Can you pass the event variable in the callback function? How does that work? That's being. So, whenever that element is clicked, JQuery is calling your callback function with that event object. So like when you. So I have an example in the very top. So, here or sometimes you call it e. You've probably seen it as like e dot preventDefault. Right? Or something, or something like that. Here you're only defining e as a parameter. So you're just saying I'm just going to call this e. But you could call it, you know, this asdf, and do it that way. So, whenever, say we had a click event on like just the body here. We click on it and at that moment, that function is called. So, this function here is called at the moment of clicking and that's why we get data for the e. So like the e object, or the event object, has data on like where you actually clicked. And stuff, and that's, so it's being passed at the time of clicking. Mmhmm? The question is how does arg get passed to isTrue and isFalse if the parameter is only set on ifElse? Let's see. One more time. So how does that arg get passed to isTrue and isFalse if it's only set on the ifElse? The function definition would have to take the parameter then use that parameter in its definition. Or you'd have to use the arguments function to, or the arguments semi-array to get access to it. So yeah. Maybe this will answer the question. So those are just example functions. But this function then is a function that takes that argument and then passes it to the function. And it will just console dot log here, x. So x is a parameter. So this is where a parameter and arguments get a little bit tricky. So, arg, at this point, is a parameter. X here is a parameter. Asdf, right, is a value that is an argument. All of these things are arguments in here. So, true is an argument. This function definition is an argument. And when we pass asdf, arg now contains that value. Arg here is now, you can imagine it's asdf. And that's an argument. And now isTrue, this x here, and isTrue is then going to be asdf. And that's how you follow it through the function. Follow up question to that, I think. Do you have to set that parameter in the function definition of isTrue and isFalse? No, you don't. So the other option is if you have no parameters, or you don't know how many parameters, you can use the arguments keyword. Which is going to print out an array of the arguments. So if we only pass one argument, and it's asdf, it'll have asdf, in an array-like object. So we covered this yesterday in the function section, if you want to review the arguments keyword. It's pretty interesting. Cool.
So I have just a short exercise for this. We're going to go back to the Functional JS Repo. And it's in the callback section. So we have this callback. Only a few, but we also have one last thing for the module pattern enclosures. That number seven, the toaster one. If you want to design your toaster. You can get started with that. So what we're doing is in the closures we're doing number seven, which is the toaster. And then for callbacks we're going to do all of them all of them one through three. And then there's also extra credit if you finish early that combines callbacks with closures. It's pretty interesting.
Callbacks Exercise Solution
So another one that we use a lot is _.map, and _.map and _.each have a lot in common. The important thing to know about _.each is that you can't return anything from _.each. So, if we see here, we're pushing to our farm, but we're not using a return statement. You cannot use a return statement in this function. It won't work so just keep that in mind. However, in _.map, it's really important what you return, so _.map does the same thing where it's going to, it's going to loop through an object or an array, and it's going to apply it to a function. The difference here is what we return, so if we return here, we return some value here, that's going to be placed into an array, and so we have to save this, in a variable, and so nums would then be again, just an array of numbers, so it would return that. So whatever is returned from the callback is going to be put into an array. So we can return num the value plus one, and then that would output two, three, four. So then you can transform your data this way. So, it produces a new array of values by mapping each value in the list, and transforming it, using this function, and the same holds true with the parameters are always going to be the value, the index, and the entire list, cool. So back to our Charisaur, sorry our pocketmon example. We have an array of pocketmons, and then we have a function called excitedArr, and this is my algorithm that takes any string and suddenly makes it an exciting string, so how do we use this, using .map? So of course we'd say _.map, and what do we pass it? How about Tanner? Pass it a one, two, three in the brackets, or no, no, no I'm sorry. Yeah, you're one slide behind. Repass it the function pocketmon. Yeah, so we'll pass it pocketmon, which is an array of our pocketmons. So would it be pocketmons or pocketmon, what do you think? Pocketmon. Pocketmon, for plural, so it's like sheep, sheep, okay. Or deer. Deer, yeah, cool. And then what do we pass? What about William, you've been quiet. Got to set that callback function, you want to call for each one of them so I think it's an excitedArr. Yep, there is no other functions on the page, and so we just pass excitedArr, Notice we're not calling it here, we're simply passing it. That's important, cool, shall we test it? How does it know that it's going to use the value, cause when you're defining excitedArr, it's just using val? Yeah, so that's just a parameter. We can call this like string two. I know but umm, maybe I-- It just the, the mechanics of _.map, how it works, is that the first thing it calls the function with, whatever function it is, whether or not it has parameters or not, It's going to call excitedArr like this. If we're just doing this example, it would be pocketmon, @, you know the first one would be zero, yeah it would be zero, and then zero, and then it would be just pocketmon. So that's what it's doing under the hood, it's calling it like that every time, and then the second time, it calls it like this, then the third and final time, it will call it like that. So and because pocketmon that gets substituted for str? And the rest just doesn't get, it gets discarded? Totally, so the first argument is going to map to the first parameter, and since str is first parameter, str is now pocketmon Question is, is passing the function in the _.map, the same as calling it? So, is it the same as calling it, so when you pass it to _.map, you aren't calling it, but _.map calls it for you, so yes and no. If you don't want this function to be called, then you shouldn't be passing it to _.map because _.map will just, under the hood it calls the function for you, really similar to in our callback exercises where we took a function and then we called it immediately. So is it, that one that you have highlighted, that's just a reference, it's telling _.map, this is where that function is, it's not actually doing the function, but then when _.map does its internal things, it's going to that address and saying here's the function. Exactly, so _.map is its own function, so we're calling _.map and somewhere in the Underscore library, we're entering into the function body of _.map, right? And we have two arguments that we're giving to _.map. And _.map has some functionality that it does always with these two arguments, so inside the function body, it's going to loop through this list and it's going to call this function with each value of the list, so as it loops, it's going to call it and that's how it works under the hood and we can even look at it if we wanted to, _.map. So, we see it takes an object and it takes an iterator, and if we look somewhere in here, we see that it's, it's calling the iterator function, so it's looping first of all, right, see that loop, and it's calling, it's doing a little bit more than, than what I'm expressing, but the main point is that it's looping, right, and then it's calling that iterator function with the value, with the property, and with the entire object, right? And so that's what _.map is doing under the hood. Cool, any questions on that? And the key thing here is we want to say this, save this in a variable because it's returning an array, so var excitedPocketmon equals this so now, we have transformed our array into an excitedArr. Could you have saved it in your same Pocketmon, one to overwrite and that should be okay?
Looping with _.map()
Cool, so knowing what we know now about _.map, maybe it makes more sense, instead of using _.each, to rewrite this using _.map. So, that's our next step and I'll give you about five minutes to get started with translating this, each function into a _.map function that saves all of our animal objects into our farm. Alright, so what's the first thing that we need to do here? Maybe do a _.map, what are we going to _.map over, do you know John? The animal names. Mm-hmm. Oh no, I ran out of animal names. So, we're mapping over the animal names, what function do we want to put here? What is it? Speak No, oh this is speak, no we want to, we definitely want to call AnimalMaker somewhere. _.map will call it for you. If you're just passing AnimalMaker, _.map is going to call it with the name. That's true, let's do it out the long way, and then we'll clean it up. So we're passing, what's being passed here? Name of the animal. Mm-hmm. And then what do we want to do next? Call AnimalMaker with that name. Yep, absolutely, name and then what else? There's a couple small minor things that we need to do. Well, we got to put in the farm, which you can do, farm = And then one last but very, very important thing. Return. Yep, we need to return it. Awesome, so now we see we've kind of condensed a line or so, we have our animal names, and we're passing each name, and we're returning it and now we don't have to do this extra operation which is pushing it to the farm, it just happens automatically, which is awesome. And as John mentioned, we can even go a step further, and just not even have this function, and we can just put AnimalMaker directly here. And then it will just call it with the name as the first parameter, so with that we could just leave it like that, and that's even shorter and then we can see, if you understand the mechanics of how _.map works, you know already that you're using animal names and you're making an animal with each animal name. So, that even makes it more clear to yourself, when you're looking back on the code and you're like, what does this code do again, I forgot, or to your colleagues who are going to pick up your code after you. And _.map's super common, everyone pretty much uses it, and should understand it, mm-hmm? So, I'm confused by what the return value of AnimalMaker is, I mean it's an object, right, but what, I guess I'm confused how this works. Sure, so whatever this function returns is going to be stored as an array, and then we're going to store that array, it's going to be farm, so _.map here, is going to return the array of whatever the callback function returns. So our callback function is AnimalMaker, so for the first loop, the first iteration with Sally, we're going to call AnimalMaker, we're going to pass the value of Sally, so it's the name to the AnimalMaker. We enter into this function body, and it's returning an object with one property on it, that's a property called speak, and which is a function that all it does is console.log "my name is ", and it says its name. But we're not calling speak, right? No, you're not calling speak, you're calling AnimalMaker and it's returning-- We're not doing anything with the animals once they get back into the farm array, so that's why I think we're kind of struggling with, the name of the function is AnimalMaker, yet it's really making-- It's making animal objects. Oh, so it's storing the animal objects in the array. And we're giving our animals the ability to speak. So if we never use this function, we'd all have just like really quiet animals, which might be better, I don't know. Now if you did access, let's say, the first index of the farm list, it'll basically spit out in a console, hi, my name is whatever that first, Sally or whatever. Mm-hmm, so we can just go ahead and delete this, and we can run this code and we can kind of look at it. And so it's important wherever you're running this code that you have the Underscore library included because it's a library, if you just run it on a new site, these methods aren't available but luckily we know for sure that the Underscore library site has Underscore on it. That'd be funny if it didn't, but. And so, let's check out our farm. So, we see our farm is three different objects with a speak function on it, and then if we wanted someone in our farm to speak, what we could do is we could say the first one .speak, and it says my name is Sally, and then we could try the next one and it will say their name, like that. And then we can investigate, that's just an object with one property, speak. Is that clear? And for those on chat who are asking about the explicit return, we are explicitly returning something here. And then also, inside of the _.map function, it's also returning in there, so.
_.map() vs. _.each
So, then let's talk about the difference between _.each and _.map. So, the important thing to note is that _.each, like I've mentioned before, you can't return anything from _.each. So _.each would be something better suited for getting each animal to speak versus if you wanted to have it return something, especially if you wanted to return an array, _.map is a better bet, however if you don't want it to explicitly return an array, maybe you want it to return an object, you might want to wrap _.each into a function where it pushes to an object instead. So, then we can run all of our code or let's get some more names, let's see. So if I wanted to _.map that into, if I wanted to use _.each to _.map it into an object, I still have to make a function, but I don't have to iterate cause _.each does that for me, and just push it onto that object. Yeah exactly, however you want to implement it, but _.map is always going to return an array. Question, the prior example had an explicit return on AnimalMaker, why the difference? What do they mean by explicit return? When you use _.map, you have to have return, but when you use _.each, you don't use return. Yeah, when you use _.each, you can't use return. _.each doesn't return anything, but _.map you have to use return. Whatever is returned from that callback function is then going to be put into the array. So, it's really important that whenever you're using _.map that you're actually returning something otherwise you're going to get an array of undefined, so if I didn't return here, we'd get, and we still mapped over it, we'd get an array of three undefined values. So, we need to make sure that we return in that callback function, whereas an animal in the, for the animal.speak is fine because we're not returning anything there, we're just console.logging. They're a little bit behind us, but the prior _.map example didn't have a return. Or maybe did I miss the return? I think when we did that one, I think what they're saying is when you did the _.map with var farm there was no return there, is that, maybe that's what they're. Like this, there needs to be a return, so if there wasn't a return, I made a mistake. Here, AnimalMaker, name, so you have to return here, because what this is saying is, so AnimalMaker returns something, and then you're returning whatever AnimalMaker returns. So, that's why there's two returns here. So I hope that answers their question. Okay, cool. We're right on time again, awesome. So, just a quick recap, _.each we can't return anything, _.map we have to return something, and it returns it to an array, did you have another question Mark? Yeah, they're just saying that by just putting AnimalMaker there that implicitly has the return? It explicitly has a return inside AnimalMaker. Right, but on that _.map, I think the last example, the short version just had, yeah AnimalMaker, so that implicitly doesn't return, right? Yes. Okay. But it's important that you actually explicitly return something inside AnimalMaker, that's the difference. Since AnimalMaker's already returning something, you didn't need that intermediate anonymous function to return the value of calling AnimalMaker because it already did that. Yeah, exactly.
And then the exercises that we're going to do is in here. We're going to do Underscore loops here. And there's going to be things in here that aren't, that we didn't cover like _.filter and you can just read the Underscore documentation to find more information on how _.filter works. And if you finish ahead of time, I have more Underscore exercises that you can dive into.
Underscore Exercise Solution
Bianca is the co-lead at Telegraph Academy, a chapter leader for Girl Develop It SF and is the SF Evangelist for Women Who Code.
Released6 Jan 2016