The full video and many others like it are all available as part of our Frontend Masters subscription.

Kyle Simpson

Kyle Simpson is an Open Web Evangelist from Austin, TX, who's passionate about all things JavaScript. He's an author, workshop trainer, tech speaker, and OSS contributor/leader.

Kyle Simpson

You Don't Know JS

Kyle explains the different module patterns that use closure. This includes the classic, modified, and modern patterns. He also discusses what to expect in ES6.

Get Unlimited Access Now

Kyle Simpson: Let's take a look at some practical usefulness for this closure mechanism and how we use this. You remember I talked about iffy being one of the most common patterns, if it's not the first most, it's the second most. And what we're about to see here is the most common, and it's what we call the classic module pattern.

Articulated mostly by Doug Crockford and others in the early 2000s. The classic module pattern has two characteristics to it, as implemented in JavaScript code. The first characteristic is that there must be an outer wrapping function that gets it executed. It does not have to be an IIFE, but it does have to be an outer function that gets executed okay?

In this case it is an iffy, we're going to have a foo pointing. The second characteristic to the classic module is that there must be one or more functions that get returned from that function call, so one or more inner functions that have a closure over the inner private scope.

So we can think about it like this object I'm going to return. Foo is going to end up pointing at this object, all of this stuff that I declare inside of here is like private members inside of a module, and this object is like my public API. And I put one or more methods on that API that have that special, privileged, closer capability to access the internal state, and that makes a module.

So there has to be, one, there has to be an outer wrapping function call. And two, there has to be at least one inner function that gets returned out and keeps a closure over the internal state.
Kyle Simpson: So if I have hundreds of lines of internal functions and variables and all that stuff, all that stuff stays completely hidden, exactly the way it would with an iffy.

It stays hidden, and we get to choose what we return back on our public API. It's the idea of encapsulation, the idea of hiding private implementation details. Comes from a principle of software design called the principle of least privilege, or also known as the principle of least exposure.

Make everything private and only expose that which needs to be public.
Speaker 2: So the outer function is like a class, and the inner functions are like a-
Kyle Simpson: Not like a class, I hate it when people call it a class It is a characteristic that we use to make modules.

So if you really wanted to give it something you could call it a module factory okay. It's not a class. People like to think these things are classes. We'll get there, why it's not a class. Yeah?
Speaker 3: If you just returned a function instead of an object with a bar function that would still be a considered-

Kyle Simpson: Still be a module probably and that's exactly what Jay cleared up. jQuery makes the dollar sign as the public API and it's just a function.
Speaker 4: There's a question about what the two characteristics of module patterns were that somebody missed something.
Kyle Simpson: The two characteristics. The first one, there must be an outer enclosing function.

Second characteristic, from inside of that function it must return at least one or more inner functions, references to inner functions that have closure over the private scope.
Kyle Simpson: All right this is called the classic module pattern. As you can see, it's a really nice easy way for us to organize our code.

You're about to get some practice with this. You better get familiar with the classic module pattern because your exercise calls for you to do exactly this. Okay, there are variations on the classic module pattern. One of them is one that I kind of like to do, it's kind of a stylistic variation.

Remember I said that that object that we return back is kind of like a public API. Rather than return back an anonymous object, I like to call it publicAPI, so I actually give it an internal reference, that I give it a name. The reason that I do that is both functionally and stylistic.

Stylistically it's kind of like when I talked about my iffy, where I pass in the window and I call it global. If I have hundreds of lines of private functions and then I see a bunch of public API doc, then I know that stuff is stuff on the public API.

So stylistically it helps me keep track of public versus private. But functionally, if you keep a reference to this object, you can actually modify your API at run time. You could add and remove method. You can update property values. If you don't keep a reference to it like in the previous slide.

We have no reference to that object. We have no way to update that object after we've returned it
Kyle Simpson: But if you do keep it around and you call it something like publicAPI, we can now reference it, as I do here. I can reference it, I can add to it, I can remove from it.

Because both foo and publicAPI will be references to the same object.
Kyle Simpson: Does that make sense?
Kyle Simpson: So I called that the modified module pattern. There's a lot of power to these variations on the module pattern. As a nice piece of homework to you. And as I said, I suggested to you, you should go home and wrap your code in iffys.

The other option is to go home and make modules out of your code. But either way, it will very easily with just a couple of lines of code you can turn your code into a much more organized thing. All right, the modern module pattern is kind of an exposition of something that you're probably already familiar with.

If you're using things like require, the AMD pattern, any of those other ones. Now I just made one up. I'm going to call mine define. I'll get to the question in just a moment. I'm going to call mine define. Any relationship that it bears to existing loaders is entirely coincidental.

I call mine define, but guess what it does? It takes a name from my module, and it takes a function that returns back an object. That should look awfully familiar, because that's a lot like how require works. And so what we see here is we see the same characteristics of the module pattern, the only thing you do not see is you don't see the execution of that function that takes that value and assigns it to a name.

That's the part that the library is doing for you. But in all ways this is still exactly the same thing as I showed in the previous couple of slides, it's still the module pattern. So those require AMD and all those other loaders, it might feel like they're really like special magical black boxes of goodness.

They're really not doing anything special. They're just executing a function and assigning the return value for you at their core, okay? So I could make one of these. In fact in my book, the Scope and Closures book, I show you a little 30 line implementation of a module manager kind of thing that does exactly what I just suggested.

Kyle Simpson: And finally, the future, or the ES6+ module pattern, as an ES6+, we're getting, I'm sorry, there was a question, yeah?
Speaker 4: Yeah on the previous couple slides, all the var foo and the define for foo are using an anonymous function, James L would like to know why you're using an anonymous function?

Kyle Simpson: because it saves space on my slides. Honest to God, that's the reason I do it. It's too much space for me to put-
Speaker 2: In production code, would you recommend a different practice?
Kyle Simpson: Should always use named function expressions. Every function you write has something that you can name it, even if it's just something generic like handler.

Speaker 2: Another one, from Oliver, he was talking about Christian Hellman evangelized the module pattern, and if this is basically what he was talking about?
Kyle Simpson: Yeah if you're talking about the module pattern in JavaScript, that's what this is.
Kyle Simpson: Absolutely.
Kyle Simpson: It's the most, if it's not one, it's two most common patterns in all of JavaScript.

If you're not aware of it, if you're not using it in your code Go home tonight and write, put module wrappers around your code, because it immediately creates more organized and more sane code to maintain. So, finally as of ES6, we're getting first class support for modules where we're not going to really have to syntactically create the outer wrapping function thing.

We're going to be able to do it In a much cleaner way, it's file based. So this is both a plus and a minus. You're basically going to treat the contents of a file like if I have a file called foo.js the contents of that file is sort of conceptually going to be treated like that exists inside of a function.

But we don't have to write the function, it's going to have its own scope. Just like it was inside of an if inference. And instead of returning things we use this new keyword called export. And you can call export one or one hundred times or however many times you want.

Everything you export will get added to the public API for that module. So you just write your variables and your functions the way you normally would you don't worry about any wrapping stuff. But, it's the way this final gets loaded that's what's going to treat it like a module that's going to give it that special scoping behavior, because the way we load it is to import.

And there are two keywords, this is a little bit strange, but there's two keywords for importing modules as of ES6. The import keyword allows you to import one or many members of the API as first class thing. So if I have on here a bar method, if I say import bar from foo it only pulls in the bar.

Not the whole module. It just pulls in part of it. If I want the whole module, I use the module keyword; module foo from foo gives me the whole thing as a traditional object reference.
Kyle Simpson: But when a file gets loaded using this mechanism, it will treat that, the contents of that file like they're a module.

So, this is syntax that's supported as a ES6. I will completely frank with you, that this is one of two things that are still in flux as of the ES6 specification process. So, it comes with the caveat that I've seen some discussion that says this line four syntax might be rejected after all.

So, there's still a little bit of flux here, but it's one of the last few things to get added, finalized for this spec, yeah?
Speaker 3: If foo.js defined two functions to be public, like export function bar, export function whatever yeah. Can you import just two of them on the same line import?

Kyle Simpson: Yeah, yeah, you can do the commas. There's a wild card so you can import all of them yeah.
Kyle Simpson: So, that's our future module pattern, but you should recognize that it's mostly the same thing. It's just a syntactic sugar, it's assuming the little function wrapper for you, and you're returning back inner functions.

Still has the same characteristics as the module pattern.

Ready to take your code to the next level?

Intense courses with world-class teachers and unlimited access to our growing library of videos for the great price of $39 per month.

Get Unlimited Access Now