This course has been updated! We now recommend you take the The Good Parts of JavaScript and the Web course.
Transcript from the "Prototypal Inheritance (B)" Lesson
[00:00:00]
>> [MUSIC]
[00:00:05]
>> Douglas Crockford: So, I think there's a better way to think about it. And that is treating the function as a module, because we've already seen a thing where we can have a self executing function and it works exactly like the old code except it's hiding that stuff. So, it's creating a scope where the stuff does not leak out.
[00:00:24] It only reveals what it wants to reveal, and that turns out to be a really useful pattern. And I wanna build functions or objects out of this because I think it's better than what the language want its pseudo classical style.
>> Douglas Crockford: So if I wanna make a singleton, language like Java that's a surprising amount of work.
[00:00:43] Cuz you have to build a class even though you're only gonna have one instance of it. So it's a class of one, doesn't make sense, but that's how you do it. But in JavaScript it's much easier. So here, I want to make an object that has two methods, first method, second method.
[00:00:59] I want them both to have shared access to some private state or some private functions, and I can do that. So I will immediately invoke the outer function, so what I assign to singleton is this object. And these objects, because of closure, will always have access to this stuff.
[00:01:18] I don't have to put this in the global space for them to share it, this is good, this is a really good pattern. And there are lots of variations on this pattern. For example, instead of returning a value that gets assigned, I could be augmenting an existing global object.
[00:01:37] Maybe I've got something called Global which is the container of all the global state for my application, I can append to it here.
>> Douglas Crockford: So this module is pattern is trivially converted into a powerful constructor pattern, so here's the recipe. Step one, we make an object using any of the means available to us for making objects including, objects literal or a new or object.create or calling some other constructor.
[00:02:09] Step two we'll define some variables or functions these will become the private members of the object that we're constructing. Step three, we augment the object with privileged methods. A privileged method is a method which is public, but which closes over the private state. So it gives it privileged access to the secrets.
[00:02:32] In step 4, we return the object. So it's a little abstract, okay, so let me turn this into a template, to make it a little easier to follow. So step one, I'm gonna make a new object. I've got myPowerConstructor which I spelled with a lowercase initial letter, because it doesn't need the new prefix.
[00:02:54] If you call this with the new prefix, all you're gonna do is waste of time, it's not gonna break.
>> Douglas Crockford: And I'm gonna create a variable called that, which is the object that I'm constructing. I would rather call it this, but this is a reserved word, I can't assign to it, so I'm gonna call it that.
[00:03:13] And in this case, I'm gonna ask some other constructor to make the object for me. That's gonna give me another dimension of inheritance, cuz whatever it does, I get the benefit from. And Step Two I'm gonna create my secret variables, my secret functions and I can initialize them now or later.
[00:03:33] Step Three, I'll create my privileged methods, I will add them to that, and the privileged methods will have access to the secret. Will have access to any parameters that were passed into the constructor, and they can also have access to that. And I return that and that's it, this is a really powerful way of creating objects.
[00:03:55] One of the benefits of this is that objects can have private state, which is something that the other forms do not give us.
>> Douglas Crockford: So, let's look again at the Gizmo object.
>> Douglas Crockford: There's just so little to like about this. One of them is that even though Gizmo inherits from Hoozit, the constructors still have to do the same stuff.
[00:04:20] So the fact that Hoozit's inheriting from Gizmo, he still has to do all the work of constructing it anyway. He has to still do the id initialization thing. So, let's do this using the functional pattern that I just showed you.
>> Douglas Crockford: So now, Gizmo is just returning a simple object and Hoozit gets its that from calling Gizmo, and add it's privileged method to it and returns it and it's done.
[00:04:48] I think this is so much nicer, I mean this is a lot less code than even the wrapper thing that we did earlier. And so much cleaner and nice I really like this, but it also allows us to do some stuff that we cannot do with the other one.
[00:05:03] For example, there's no privacy on the ID in these. Suppose I want ID not to be a public property of the object but to be a private property of the object that is only access indirectly through its methods. Okay, maybe I have security or other considerations that want me to do that.
[00:05:23] Trivial to do in this model, so, in fact, adding that privacy actually makes the code smaller. I simply don't add ID to the object literal, cuz it's gonna be private now, and instead of saying this.id here, just saying ID there. So, that function, the two string function will close over the ID that was passed into Gizmo.
[00:05:50] And we have a similar benefit happening in the Hoozit. Its test function gets closed over the variable that got passed into Hoozit, so code is actually smaller. We have other things we could do, if we want to simulate package scope which I think is one of the big bad ideas in programming languages, but we're kinda stuck with it.
[00:06:12] And if you want to simulate it, you can have this secret object, which is another parameter, that contains the shared state. That is essentially the packaged scope, that these guys can pass through each other. So that's an option that we have now, we can have super methods now.
[00:06:31] It turns out, we don't need super methods, super methods are one of the powerful ideas in the classical model. And when I started in JavaScript, one of the first things I did was figure out a way to write super methods and never used it. You just think about things so differently that the super model just doesn't come up.
[00:06:50] We have so many other ways of composing functions, that particular one is like the least interesting one possible. And so, there's no prohibition from using supers, it just outgrows them really quickly. But if you feel a need for them, this pattern gives us a way to do them.
[00:07:12]
>> Douglas Crockford: So let's look at a couple of tricks we can do with higher order functions. Memoizers are like cashes but the mathematical so they're better, which allow you to remember previous values that a function has computed. So if you're ever asked to compute the same value again, you can simply look it up.
[00:07:33]
>> Douglas Crockford: So let's look at what our memoizer does. It first creates a function called recur and then it returns that function result, so that's pretty easy. So let's say we want to compute factorial, we'll pass to memoizer an array of the first two values of factorials. So factorial of 0 is 1, factorial of 1 is 1, and then we'll pass it in a formula which it can use for computing all of the other values.
[00:08:00] And it will take a recurrence function as well as the value that it needs to compute, the recurrence function allows it to call itself, so it can do recursion. So, to find any factorial of n, you return n times the factorial of n- 1. So looking at what happens when we call recurring there, we go up to that function, we look to see if the result we're looking for is already in the memo array.
[00:08:30] If it is, we simply return it and we're done. But if not, then we'll call a formula and take its value and store it in the memo array for next time, and return that as well. So, that really pays off on things like Fibonacci, a recursive definition of Fibonacci is explosively expensive.
[00:08:52] As n starts to get bigger, it gets so slow, because you're constantly recursing on two legs which multiply in four and gets really expensive, but with memorizer it is linear. So even though this appears to be more code maybe doing more work, it is avoiding massive amounts of work.
[00:09:16] So this is a huge optimisation over a naive recursive implementation factorial. And it all happens by using functions as arguments.
>> Douglas Crockford: One warning about functions, do not ever declare function in a loop. This is bad for two reasons, the first one, is not that important but. You pay a cost in creating a function each time you encounter in a loop, so, that's time and memory.
[00:09:46] Much more important is that the function closes not over the current state of the loop, but over the whole function, because that's how JavaScript works. Which can cause things to go wrong. For example, here we have a loop that's going over an array of DIVs and it's actually adding an on click handler to each of those elements.
[00:10:13] With the idea that, when we click on it, it should alert the number of the element. And so if we pass an array of 4 DIVs, we want to click 0, 1, 2, 3, but what you'll actually get is 4444. And the reason is, that function is closing over the current value of i, not the value of i at the time the function was created.
[00:10:36] So we're seeing i at the end of the loop, at the end of the loop it's four. So the way you get around that is, you move the creation of that function outside of the loop. And it turns out the solution to all most all of life's problems is write another function.
[00:10:53] So in this case, we'll write a make handler function which will return that event handler. And that moves that stuff out, provides a mechanism which will create the closure, which will preserve the value of that variable that we want and everything works.
>> Douglas Crockford: I'm not gonna discuss this except to mention this is one of the most strange and amazing attributes of computer science, it's the y combinator.
[00:11:23] It is a lambda expression which makes it possible to have a function recursively call itself without using recursion, and without using variables. Absolutely no practical benefit to this at all. Except it's something that's weird and abstract, and is trivially expressed in JavaScript. The language is so expressive that it can talk about lambdas to such an extent you can actually do this stuff in JavaScript.
[00:11:52] JavaScript is an AI language, it's amazing.
>> Douglas Crockford: And so JavaScript has good parts we all know, so if you wanna know more about this stuff, I highly recommend a book called the Little Lisper, this is review of that book. It's this wonderful programmed learning text which is all about recursive functions, and it's great.
[00:12:14] If you want to understand more about recursion you definitely need to read this book. It's now in a later edition called The Little Schemer, I think it's on its fourth edition now. It's on Amazon and everywhere, I highly recommend it. So let's take a break, and get out some paper and pencils, and we're gonna do some work next, yeah?
[00:12:39]
>> Speaker 2: Is this the [INAUDIBLE] example, where you're trying to loop assigning the variable hwre you pointed out, where all the [INAUDIBLE]. If you put in fact var equals inside there simingly assigning to a global temp, because a global temp is actually move around of the loop to it's does that make sense?
[00:13:04] There's no scooping it wide, then it's all gonna be seen local valiable.
>> Douglas Crockford: It depends, yeah t depends on which function you saying. So what we did was essentially move that variable into where it's not gonna get changed on each iterations.
>> Speaker 2: Yeah, so where you've got div_id =, that was var div_id =.
[00:13:24] That was up above [INAUDIBLE] higher up in the for loop, way up, yeah. If you have var d id = right there.
>> Douglas Crockford: No, that doesn't help, cuz it's still in the same scope.
>> Speaker 2: Cuz it's going to move at the same scope, and not within the for loop.
[00:13:41]
>> Douglas Crockford: Right, yeah, function's this-
>> Speaker 2: That's sorta subtle.
>> Douglas Crockford: It is subtle, and so I tried to find the simplest possible rule to give people to know, watch out for that. So the simplest rule I could think of was don't make functions in a loop.
>> Douglas Crockford: Move it outside.