Check out a free preview of the full The Good Parts of JavaScript and the Web course
The "Module Pattern" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:
The module pattern is a much better technique for creating reusable objects through inheritance because function scope can be used as a container for private variables and methods. This eliminates the need to create global constructor functions or objects with “leaky” APIs. Doug demonstrates how the module pattern is easily transformed into a powerful constructor pattern.
Transcript from the "Module Pattern" Lesson
[00:00:00]
>> [MUSIC]
[00:00:03]
>> Douglas Crockford: I think we can do better than that and I think the way we do better is by going back to the module pattern. That we can take any bunch of stuff and put it inside of a function and invoke it immediately and it does the same thing except that in this space, we're not creating global variables.
[00:00:22]
This stuff is not leaking out in creation where it's a danger and a hazard. So we can make stuff using this pattern. For example I want to make a singleton. I want to make one instance of an object containing two methods, first method and second method, and I want those two methods to share private variables and private functions.
[00:00:50]
In JavaScript there is no easy way to get privacy except when you're doing this stuff with with module or function modules because each function has a function scope. Which is a really effective container for keeping stuff that nothing leaks out of function scope ever. There's no force in the universe that can force a function to leak what is held in its scope.
[00:01:15]
And we can take advantage of that. And it's a very nice pattern so what I'm going to store in singleton, is not this outer function because I'm going to invoke that function immediately. What I'm going to store will be its return value, which is this object containing two methods.
[00:01:30]
And those two methods will close over the private state. And those two methods will share that private state. If one changes one of those private variables, the other, next time he looks at that variable, he will see the change.
>> Douglas Crockford: Before we figured out how to do this stuff with functions in JavaScript, the private variable and private function would have been global variables, and there is no privacy there.
[00:01:58]
>> Douglas Crockford: And one nice thing about this compared to a classical language, in a classical language if you want to make a singleton, you still have to make a class, which is a lot of work just to make one thing. Whereas in JavaScript none of these are very much work.
[00:02:14]
And there are lots of variations on this pattern. For example I might have, instead of returning an object I want to have a global variable which is going to be the container of everything in my application. It's going to be this one object which is the root of everything.
[00:02:30]
And I want to enhance it, I want to add a methodical property to our global object that has these two methods in it which share this private state. And we can do that easily. So we don't have to make a class just to make one off, and again there are lots and lots of variations on this pattern, it's a very rich pattern.
[00:02:50]
And again this works because we're invoking the function immediately. But if we don't invoke the function immediately, then we can hold onto that function and make lots of instances. So let's do that. This module pattern is easily transformed into a powerful constructor pattern. So here's the recipe. Step 1, we're gonna make an object using all of the techniques, any of the techniques available for making objects.
[00:03:16]
We can use an object literal, we can use new, we can use Object.create. We can call another of these power constructors. Any way we can get an object, we get an object. Step 2, we will define some variables and functions. These will become the private members of our object.
[00:03:37]
Step 3, we will augment the object with privileged methods. A privileged method is a publicly available method of an object which closes over the private stuff. And step 4, we return the object. So it's a pretty simple recipe. It's way too abstract to make sense out of it, right?
[00:03:55]
So we need to go a little deeper. So let's turn it into a template. So step 1, I'm going to make a constructor function. And I'm spelling constructor now with a lowercase c instead of an uppercase c, because this form of constructor does not care about the new prefix.
[00:04:17]
If you call this function with a new prefix it will run a little bit slower, but it will still do exactly the right thing. So, this way we don't have to worry about people forgetting the new prefix cuz nothing can go wrong. Then I'm gonna recommend passing in a specification object.
[00:04:36]
The way you normally write constructors is you'll just pass in some number of things separated by commas. Some years ago, I designed a constructor that had ten arguments in it, which was a problem because nobody could remember what order they went in. So it was really hard to use and then it turned out nobody used the third parameter.
[00:04:58]
But we couldn't take it out, right, cuz if we took that argument out, then all of the code would break. And so people had to use the third parameter unnecessarily forever. That was really awful and brittle. So, what I would do instead is say pass in an object using an object literal.
[00:05:16]
So, by just adding two more characters, we can now have named parameters. I can give each of the parameters a name so, the call is self documenting, so we can see what's getting passed in. We can have them in any order, if we leave things out we can have nice defaults, if it turns out some parameters become unnecessary we simply ignore them.
[00:05:36]
We have lots of power in the way that we can manipulate objects so I would take advantage of that. Also, we could get the specification object from a JSON payload. So we might have some store that we want to use the constructor to reconstitute the object. We can do that as well.
[00:05:53]
Or to cause the creation of objects across the network using specifications to get passed over the wire through JSON. Then I'm going to call another constructor to make an object and I'm gonna pass the same specification object to him as well. So it maybe that that other constructor will make use of some properties in the specification object that I don't need but that makes sense to him.
[00:06:18]
And if there's anything we both need we're sharing it. I used to call this parasitic inheritance where we're gonna call another constructor and we're gonna take credit for its work. I was inspired by a wasp that lays its eggs in the bodies of live spiders. So the spider does most of the work of making instances but the wasp gets all the credit, gonna do something like that.
[00:06:48]
And then I'll take the result of what the other maker did, and put it in a variable called that. I can't put it in something called this because this is a reserved word. Then I can create my member variables. I can create as many member variables as I want.
[00:07:05]
And because they're gonna be held in the function scope, they're not visible outside of the object, they're only visible inside the object. I will create my private methods, and my private methods will have access to the specification object to the member variables and to the other methods as well.
[00:07:23]
I do not use this in here, don't need this, so the code's going to be a little bit smaller and cleaner. And any of these methods that I need to be public, I simply assign them to the outgoing object. And the last step, I return the object. And that's it.
[00:07:44]
And it's a very flexible pattern, there are lots and lots of variations on this but this is the basic core idea, that we're taking use of closure in order to provide private state within the object.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops