Transcript from the "Three Pillars of JS Solution" Lesson
>> Kyle: Welcome back. I'm sure you're eager to see exactly how we bring all of these little pieces together in this exercise. So let's start by looking at those instructions. We're gonna start with item number one. It tells us straight up, we wanna look at the printFavoriteBooks function. And specifically we wanna zero in on whether there's an accidental type conversion that's happening.
[00:00:20] That's otherwise known as an implicit type conversion. And there's a little hint here that says if we've got something going from a number to a string, we can use the String function to modify that. So let's look at the printFavoriteBooks function. And you'll notice right off the bat that there is a value here that we know is a number because the length property of any array is a number.
[00:00:41] That number is being included inside of a string, which means that it's automatically or implicitly being converted from a number to a string. Now, the truth is there's no big problem with converting numbers to strings. That's a pretty safe type conversion. And most developers probably wouldn't be that concerned about allowing that implicit coercion.
[00:01:01] But I do just wanna point out, just for the sake of practice, that there's a way to be more explicit about it. And that is to wrap that call to favoriteBooks.length in a function call to the String function. So if I put String around the favoriteBooks.length, now we are explicitly saying, make sure that it is a string value before it's concatenated or before it's dropped into the larger String volume.
[00:01:26] It won't change any of the output of your program, but it's just being a little bit more savvy, a little bit more aware about your types. And even if it wasn't a problem now, it is potentially some sort of bug later. So anything you can do to make your code be a little bit more clear, a little bit more expressed and obvious.
[00:01:44] That will help you down the line. That's a really important practice to pick up as a developer. Okay, let's go back to the instructions. Let's look at number 2. We wanna move the addFavoriteBook and printFavoriteBook functions into the Bookshelf class. And now we're gonna make the methods. And there's a really important hint here, which is the class methods.
[00:02:04] If you remember from the slides a little while ago, they don't have a function keyword in them, they're just the name there. So we've got to take the function keyword off, and also don't miss this part. And because they're gonna be methods, we're gonna need to update them to use the this keyword.
[00:02:20] So that we are referencing our instance of our class. So I will do this one at a time. I'm gonna take the addFavoriteBook function and we're gonna move it inside of the class definition for bookshelf. I will indent it one. You'll notice even by my syntax highlighting, it can tell that the word function doesn't belong here.
[00:02:41] That's why it's white, so if we take that off. Just like with our constructor, now we are defining a class method. A class method called addFavoriteBook, which still takes in a book name. But what's important now is that favoriteBooks is no longer a variable that we're gonna access through lexical scope.
[00:02:58] We're gonna access that through the this mechanism and the prototypes mechanism. So what we need to do is prefix that reference to favoriteBooks for the this method, for this reference. Remember whenever we call somewhere, an instance of this Bookshelf class, we're gonna be saying something .addFavoriteBook. And that something that .addFavoriteBook is gonna tell addfavoriteBook to use a this that's pointing at that something instance.
[00:03:28] So that's why we want to make it a this aware method. We'll do the same thing with the printFavoriteBooks. We're going to move that inside of the Bookshelf class definition. We're gonna take off the function keyword, so that is a method now. And then, we have two references to favorite books.
[00:03:47] We've gotta make sure to put the this dot in front of both of them. If you don't end up putting it in front of both of them, you won't access the correct one. It'll be trying to find a global variable of that name, it won't find it. Things will break, you'll cry.
[00:04:03] So just make sure you make your functions, your methods, rather, be this aware. Okay, we're making some good progress. Let's go back to our instructions. Number 3 in the instruction says first to fill out the definition of the loadBooks function. Remember that's outside of the class, it's not a method, it's a function.
[00:04:23] It's outside of it, and we're gonna fill it out and it's going to receive as a parameter an instance of theBookshelf class. So we're gonna have some kind of Bookshelf that we're passing in. Some sort of Bookshelf instance. So we've already got the loadBooks function kind of sketched out here.
[00:04:42] We're gonna need to name some kind of parameter, and I'll just say theBookshelf. For lack of a better name for it, we'll say theBookshelf, which is a specific instance of the general Bookshelf class. Now, instruction number 4 says that loadBooks should call what we've already been provided as a fakeAjax function.
[00:05:07] And we're gonna pass along a variable called BOOK_API and we're gonna write and pass along an inline function expression. That's a big old bunch of stuff. Let's break that down one at a time. First of all, we have a fakeAjax function that I've already provided. You're not supposed to change anything about it.
[00:05:23] But it's just here just to demonstrate the idea of making an Ajax call without all the complexity of needing a server to actually talk to. Okay, so fakeAjax we can see expects a URL and expects a cb, a callback, which is going to be a function that we invoke.
[00:05:40] And you'll notice that that function is gonna get called with an array of book names. Okay, so what we need to do then is in loadBooks, we need to actually call fakeAjax. And what we're gonna pass to fakeAjax, first we're gonna pass it a URL. And we have a variable called BOOK_API that we can pass in.
[00:06:02] So when we pass in BOOK_API, the way we're able to access that, by the way, that's lexical scope. This function doesn't have a BOOK_API variable, but it does have access to the outer scope, which has BOOK_API. Now we are gonna need to pass in, the instruction said, an inline function expression.
[00:06:21] So we are gonna write a function and I wanna give it a name, I don't wanna use anonymous functions here. I want to give it a name and I'm going to call this ,onBooks. Because I know that this is loading my books and so onBooks is indicating that I have received them back.
[00:06:36] And so the parameter name that I'm gonna get, remember it's an array of book names, so I'm just gonna call it, bookNames, plural. I'll put those curly braces there. And now, this is a in-line function expression. It's a name function expression that's gonna get invoked whenever cb is called.
[00:06:56] That’s gonna be calling our onBooks function and passing an array of book names. Now, let’s go back to the readme and check what item 5 says. It says the callback's gonna be passed an array of book names. We should loop through this array and pass each book name to addFavoriteBook method on whatever instance we’ve passed into to loadBooks.
[00:07:20] So we passed in this theBookshelf instance and it's the thing that has an addFavoriteBook method on it. So we're gonna actually call, we want to loop through the book names, remember loops. We're gonna do another for of loops, we'll say (let bookname of booknames). And for each of these book names we want to say theBookshelf dot., and the method we gonna call is addFavoriteBook.
[00:07:56] Remember what I was saying just a little while ago, here is our function call site. Using the implicit binding, it's gonna invoke this method, the one from line 6. But it's gonna invoke it in the this context of our instance which is theBookshelf. And that's the thing that's holding this copy of the favoriteBooks array.
[00:08:18] So we wanna pass in bookName to the theBookshelf.addFavoriteBook method. Now, after that for loop finishes, all of our book names should have been added into our instance of theBookshelf. And lastly the instructions tell us that we should call the printFavoriteBooks method on that same instance. So we're gonna say, theBookshelf.printFavoriteBooks.
[00:08:50] And again, here's our implicit binding. The printFavoriteBooks() function knows that it should be invoked with a thisKeyword that is pointing at theBookshelf.
>> Kyle: Last step then, it says in item 6 that we need to create an instance to Bookshelf class and pass it in as an argument to loadBooks.
[00:09:14] So let's try that. Let's say, we're gonna make an instance, so I'll call it as myBooks = new Bookshelf. That's for instantiating an instance of a class. And then we're gonna call loadBooks and we're gonna pass in myBooks. And that should invoke our function. There will be a delay, remember this setTimeout, it's gonna delay.
[00:09:43] But because of closure, it still knows about theBookshelf, that's our closure being used across that function boundary. Still knows about theBookshelf and it's able to invoke methods on it. And then those are able to get a thisContext for our instance. So with all those pieces in place, let's cross our fingers.
[00:10:03] And let's go over to a runtime environment, like runjs, and lets test it and see how it works, and there we go. If I scoot this over, we can see it did, in fact, print out our favorite books, 3. And our list of our three favorite books and it did that by pulling those from the favoriteBooks array that is on our instance of the Bookshelf class.
[00:11:28] Start from the blank empty file or from the original file. Try it from scratch and make sure to practice each of those things. And maybe even try changing a few things. Maybe make a few instances of Bookshelf and try to make a few different calls and passing different results.