This course has been updated! We now recommend you take the Deep JavaScript Foundations, v3 course.
Transcript from the "Exercise 2: Solution" Lesson
[00:00:00]
>> [MUSIC]
[00:00:05]
>> Kyle Simpson: Again, there are no cases where there's an absolute right answer. But I'm going to give you kind of a basic first pass at how we might construct a module pattern for this code. The first thing to note is that we've got this variable that has data in it, and if you read the read me, you'd see this is not data we want to internalize into our module.
[00:00:26] So we're gonna wanna take that stuff, kinda probably move it down to the bottom, cuz we're gonna deal with that in just a moment. So I'll just move that down and out of there. But to create our module, what's the first step that we need to do? We need to create a variable that's gonna be our module instance.
[00:00:42] I'll call mine NotesManager. You can call it whatever you want obviously. In this case I'll do an IIFE, although it's not technically required that it be an IIFE. I will indent all of that just for good measure, and then I'll close out my IIFE. And now that I've got an IIFE, I've accomplished the task of making everything private.
[00:01:07] So I've at least made that task already. But that's only the first part of our module pattern. The second part of our module pattern is we need to return a public API. So, we're probably gonna want to do something like publicAPI equals, and have some object here, and then we want to return that publicAPI.
[00:01:30] The readme told us that we needed two different methods for our API, one we called init, and we already have an init method, so I'll just make it a reference to the existing init method. And then the second one, it said you could call it whatever you want, I call mine loadData, but you can call it whatever you want.
[00:01:50]
>> Kyle Simpson: I need to actually implement that function, so loadData, the purpose of it is to take [COUGH] an array of records and add them to our existing internal array. So we can say data, and we can say notes, which is gonna be our internal array, is equal to notes.concat(data).
[00:02:16] So we wanna keep a internal notes array that will start out initially as empty, and then we have this load data function. Now, that's all I've had to change and I've created myself a module. Cuz you'll notice that I have a notes manager variable, it's an instance from my module, it's getting an object that has two methods on it, init and loadData.
[00:02:40] So I can come down here to the init and that would change to be NotesManager.init, and then I need to do something with this notes array so I would say NotesManager.loadData.
>> Kyle Simpson: So I'm passing in an array of my data. Now, we're just kind of hand waving and pretending that, that data comes from a database or from local storage or whatever.
[00:03:17] But we're loading in this data, pushing that into our NotesManager and then calling the NotesManager.init when the DOM is ready, using the jQuery's DOM ready event. Yeah.
>> Speaker 1: This is kind of a weird question maybe, but your IIFE up at the top.
>> Speaker 1: You say bar notes manager equals anonymous function?
[00:03:41] If you were to say function and name that function capital N notes, capital M manager, what does notes manager refer to in the global scope?
>> Kyle Simpson: In the global scope, it's only this one, because remember with the function expressions, this name doesn't refer, it's not bound in the outer scope.
[00:03:58]
>> Speaker 1: Okay.
>> Kyle Simpson: So this name would be bound only in the internal scope and not in the outer scope. So the outer scope would only have this variable and what would be confusing here is that in the interscope you would reference a notes manager which referenced the function.
[00:04:14] But in the outerscope, Notes Manager would reference the return value from the function call.
>> Speaker 1: Right.
>> Kyle Simpson: So that would be kind of a confusing thing, but you could certainly name this thing, module factory or whatever you want to name it.
>> Speaker 1: Okay.
>> Kyle Simpson: The other thing to point out is [COUGH] everybody see so far, any questions about how we constructed our module?
[00:04:42] You can see it took very little code to take a big file of spaghetti code and organize it into a well thought out module. And, in general, that's what you'll find, it doesn't really take as much code as you might think to turn your code into a module.
[00:04:58] Couple of things to point out, first off I said we don't actually have to use an IIFE. In this particular case I used an IIFE because I only needed one module, so it's sort of like let's just take my little module factory and automatically call it. But what if I did theoretically want to be able to make multiple modules.
[00:05:17] Well all I have to do is take it from being a IIFE to just being a plain old function, and then instead of using NotesManager as an instance, I can say myNotes equals NotesManager, and your notes equals notes manager. And I can make multiple one's of those by simply calling the factory multiple times.
[00:05:43] And instead of calling loadData I say myNotes.loadData and MyNotes.init. Does everybody see that? So modules don't require an IIFE, but a lot of times I would say the vast majority of times that I've experienced, you create modules and you only ever need one of them. In fact, I would go so far as to say, I very rarely have ever seen anybody need multiple instances of anything.
[00:06:10] It just isn't that common in JavaScript. We think theoretically, I'll create these classes and I'll be able to theoretically instantiate hundreds of them, and in reality we only ever create one or two of them anyway. So for me, modules and the IIFE pattern, they work pretty well. We did note that there on lines 110 and 111 we'd be creating multiple copies of all that internal function.
[00:06:34] So there might be some downside if you were legitimately gonna create lots of module instances. Slight performance downside. Probably not a big deal, unless you're creating maybe tens of thousands. But most of the time, we end up only creating one, anyway. So Singleton powder works well. One other thing just to point out real quick, I won't belabor it but there is a mention in here, this point four down here, it talks about the structure of our code with relation to our dom references.
[00:07:07] So you'll note the inside of my code I've got a whole bunch of manual references to dom id's, and that's not a very good robust pattern for a module, because now I'm required to have the exact same dom structure everywhere for this to work. It's not that difficult for us to abstract some of that away.
[00:07:28] So one quick pass at how I might do something like that is I might have-
>> Kyle Simpson: I'll just do one of them, but you can note how we would do many of these. I can say that notes, and by the way my convention for jQuery is I put dollar sign in front of variables that are jQuery references.
[00:07:49] It's just a convention, it's not a requirement. So I get a jQuery reference to the selector that I pass in, and then everywhere, instead of saying this, I just say $notes. I just reuse that reference all over the place. And then to pass that in down here in the init,
[00:08:21]
>> Kyle Simpson: I pass in an object that has that selector in it.
>> Kyle Simpson: Does everybody see how I did that? And I could do that for all of my dom references. I could pass them in from external and very quickly I've turned my module from being kind of hard coded against a particular dom to being much more generalizable against multiple different kinds of dom.
[00:08:53] Those are the sorts of things you want to think about when you are modularizing code. You want to think about that reusability, the flexibility, how general can we make it without having to go too far in terms of modifying with code. All right, anymore questions on exercise two?
[00:09:18]
>> Kyle Simpson: I see in the chat that there's a question about, why did I put the function here? So this is a very common question. If I were to take out this function wrapper, and I were to simply call my notes init like that, the problem is that I'm not actually deferring that function call to be on document ready anymore, because this function call will happen right away, and whatever his return value is, is what would get passed in to the ready function.
[00:09:46] Which is not what we want. We want for the init to not happen until after the dom ready is fired. So if we need to pass in parameters like that, we have to do this function indirection.
>> Kyle Simpson: Hopefully that answers James's question on the chat room.