What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Advanced JavaScript
by Kyle Simpson
Gain an advanced understanding of the core mechanics of how JavaScript compiles, optimizes, and executes in the browser.
Resume CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Recommended
Introduction
Speaker Introduction
(Introduction) Thank you all for having me. I appreciate everybody here in person, and also all of you online from all parts all over the world. Thank you for being here. it is an honor to be back. I always joke that, 'cause I travel, you know, speaking and teaching for a living, so I always joke that I can judge a city based upon the weather that they provide to me when I visit, so I showed up last night to the cold and rain, but I appreciate Minneapolis hosting me a second time. Mark's right, I was here about a year and a half ago for a web performance workshop, so I'm well familiar with this space and glad to be back. Mark runs a fantastic workshop series. Like I said, I go all over the world and I hear just random people at a conference somewhere in a different part of the world talking about a video they saw from this. So you guys are incredibly lucky to be part of that. I encourage you to continue to do so, continue to spread the word. I'm very pleased to be also helping with that. As a slight side note on that particular, on that web performance workshop, I'm slightly embarrassed by it, although I think there's lots of great content, but that actually happened to be the very first workshop that I ever taught, long-form workshop. I had done plenty of speaking before, but Mark kind of gave me my start in teaching, and I didn't even really know at the time. He kind of contacted me out of the blue and said I've seen you speak, what would you think about teaching? I had kind of a bent towards teaching, but I'd never really done it in this industry. And so I was excited to kind of try it out and see, and I was insanely nervous the night before, not knowing if I had too much content or not enough content. I had no idea, really, what I was doing, but he gave me a shot, kind of an unknown in terms of speaking and teaching, and that actually, I didn't know at the time, but that launched the career that I now have. So I now do this full-time, and I appreciate Mark for giving me my start. So it's good to be back here. So I'm Kyle Simpson, known as getify online. If you're into that online stalking thing, you can check out all kinds of links to where to find me and provide feedback. Whether that be questions, whether that be telling me that I said something that you completely disagree with, that's totally okay. But getify.me has links to all kinds of things about me. As I mentioned before, what I spend my time, full-time doing, and I say full-time kind of with some air quotes because I don't actually work full-time at it, but it is the only thing that I do that I pay my bills with, so I call it my full-time job, and that's teaching, and that involves corporate teaching, so a number of big companies that I travel all over to do teaching for, intels and things like that. I also do public workshops at a lot of places when I go and do, when I'm in some city for a conference. I just did a public workshop a few weeks ago while in London, so I know some of you that are online were part of that process as well. So welcome to you there in London. So I teach for a living now, and just as a little plug for that, if anything that I say is interesting, if you find this stuff interesting, and useful, I encourage you to go back and talk with your companies, talk with your meetup groups, things like that, anybody, and I'm available for hire. So I can travel anywhere to teach, so I'd love to do that if that would be helpful to you for your company or your group. The other part of my time that I spend, so I spend about maybe 50 to 75% of my time doing that, but the other part of my time I spend on what I call community building, and this involves a variety of open source activities. Open source development, writing on the books, which we'll get to in just a moment, speaking at conferences, running meetups and things like that. And so my goal is to sort of, it's an all-boats rise with the time, my goal is to build awareness about the web platform and about its technologies so that more people are aware of it, more people appreciate it, and by the way, the word appreciate doesn't necessarily mean like. It just means to respect, understand, to realize the usefulness of. So my goal, I'm sort of, I'm an independent but I'm sort of an open web evangelist, and my goal is to go everywhere and try to evangelize what the open web platform can do, and try to help people learn that better. And I feel like the more people that appreciate that technology, the more opportunities that'll give me to teach. So to that end, some of the time that I spend, I do quite a bit of open source development on a whole variety of things, if you check out my GitHub. Just mention a couple of quick projects that I work on, so LABjs is the one I'm probably most known for. LABjs is a dynamic script loader. it's about, it's coming up on five years old now, so it's actually getting to be rather ancient in terms of open source technology. But it is probably it's more important feature is its stability, because it's almost three years since the last time it had to be changed. Now I know many of you know about open source projects that every couple of weeks they're releasing another patch and adding a new feature and things like that, but I consider stability to be its most important feature because it has been battle-tested, it's been hardened, it does exactly what it's supposed to, no more, no less, and it continues, now I maintain the project in terms of, you know if there are bugs or things like that, I get people posting issues from time to time, and we track them down and it turns you, you know, it's not actually a bug, but if there was one, we would certainly do that. It's been in use by big companies like the Zapposes and Twitters and Vimeos of the world, so you can trust that it has been put to the wringer. it's just a really low-level simple script loader. It's not at a higher level in terms of dependency-management, things like Require, you know, that have lots of complicated configuration. It's nothing of that nature. It's just, load some scripts and get them done as fast as possible, ensure the execution orders and dependencies are met. Now, why would I even bring up a script loader these days? Because a, we have these dependency managers, and that's what everybody in the world seems to be using, and b, we all know that the simplest and easiest way to get all your scripts loaded is just to concatenate everything in a build process, right? So why would I even talk about a script loader? Why would LABjs even matter? I have a prediction, and I don't even know if it'll be true, but I have a prediction that we're going to see a renaissance in script loader technology. it's kind of fallen by the wayside, it doesn't get a lot of attention these days, but we're seeing a switch in our platform technology, and that is the advent of HTTP 2.0. Or HTTP 2. And it's not, that's not quite like IPV6, where people have been talking about it for a decade and yeah yeah yeah, maybe someday we'll actually get IPV6. HTTP 2 is a reality. It's already happened in all of the browsers that you're using, probably are already supporting it. A number of the big web services out on the web, they're already serving up over HTTP 2 if your browser's capable of it under the right circumstances. And why would I bring that up? What's the big difference about it? Well it turns out that with HTTP 2, everything that we learned about optimizing our web page load performance to reduce the number of files, combining everything, combining all our JavaScript into one file, all our CSS, all our images into sprites, everything that we learned there, it turns out that's the worst possible thing that you can do in HTTP 2. Because the HTTP 2 protocol is a persistence socket protocol, much like web sockets, it establishes one handshake and then it interleaves bits and bytes, and you know, leaves the files and downloads everything in parallel, so if you have one giant file it can't really do that and you want to have as many small chunks and small files as you have. So we've all spent the better part of the last five years building out hundreds of tiny little AMD files and we've got these build processes that are putting them all into one big file and shipping it out to the browser. I predict that over the next year or two we're going to see, people are still going to have hundreds of little files, and how are they going to load those things when they have to switch to loading them all as separate resources rather than as one? And I predict that we'll see a renaissance of script loading technology, it'll be people trying to figure that out, and I also predict that LABjs will just be patiently waiting in the corner if anyone wants to check that out. So you can take a look at LABjs if you want to look at performance script loading. Grips is a templating engine that I wrote a couple of year ago, I've been kind of tinkering on it for a while. Now it's not 'cause there's not a thousand other templating engines out there, there certainly are, but there are some problems that I've seen in sort of the front end templating world. So I kind of group templating engines into two extremes. On one end of the spectrum, we have templating engines which are extremely, you know, what they call logicless, like it's extremely stripped down, there's little logic or not logic as possible. Many of you are probably familiar with Moustache and variants thereof. They call themselves logicless templates, or sort of, you know, zero-logic templates. And the idea behind that is that we don't want to put business logic inside of our templates, so let's make a templating engine that has no logic. Ergo we've solved our problem, because you can't put logic inside of the template. And the spirit of that is great. Obviously, I totally agree with the idea of keeping these, you know, keeping the separation of concerns, keeping our business logic out of the templates. In practice, however, I've tried using those in production systems, and in practice what I find out, what I find is that there's an awful lot of tinkering with the data, of massaging it to just be just right inside of our controllers because there's very little flexibility in the frontend layer, so we have to massage the data to be just right. We sometimes have to pollute our data model with what we call presentational data, so if you want to loop over the months of the year to put in a drop down, we have to stick that data alongside of your data model and ship that off into your template, because the expressiveness of the template engine restricts you from doing that sort of thing. So unfortunately, while we were trying to create a separation of concerns between our controller and our view, we ended up creating this really brittle tie between the two. And you have to really understand your view to write your controller, and you have to really understand your controller while you're writing your view, and vice versa. So the theory is great, but the practice somewhat lacks. And that's, you know, a common theme among a lot of things in the web technology world. On the other end of the spectrum, from logicless templates, we have this idea that says, well, I do need to do some logic, so why don't we just use the standard language that everybody knows, let's just throw a whole programming language inside of the templating engine? As a base example of that, PhP is a templating engine with the PhP programming language embedded inside of it. other examples that you may be more familiar with, Dust, and Handlebars and other things like that. You know, they have the JavaScript language or the full Ruby language or something like that as your expressiveness inside of your templates. and I liken that to me handing you a pile of rope and I can say, I can either teach you with this pile of rope to build a rope bridge, which is quite helpful, or I can teach you to build a noose, and that's not quite so helpful, at least in some circumstances. And the problem is that under the pressure that says your boss is breathing down your neck and says, hey, you've got 10 minutes to get this thing in there, we need, you know, some logic around this thing so that it hides under certain circumstances. When you have the ability to put an if-statement inside of your templating engine, and your boss says, you got to get this done, that's the expedient way to do it, we put an if-statement there. And then we maybe make ourselves a comment that says come back and our little, our famous to-do, fix this kind of comment, come back and fix this, which we know we're never actually going to come back and do, but you know, the spirit of it is great. We want to fix it. And then six months later, it's not even you, it's somebody else on your team, the boss is breathing down their neck saying, hey, there's another condition now that needs to be wrapped, so then they go in and put in, you know, and, and some other condition and call out to some other controller method, and before long you see that you've got business logic leaked into your templates. And the pressure behind the expediency says just do what's quick, and then theoretically we'll come back. I have this book that I want to write some day called the Myth of the Refactor. We all like to think that we're going to refactor things in practice, you know, there's millions of lines of code being written every day, and most of those lines of code will never be seen again by another human being. And that's kind of a sobering fact to think about, but it's kind of a reality that we deal with. So there's this tension between no logic, too much logic and where is the middle? It's kind of the Goldilocks, could there be somewhere in the middle that satisfies the needs but doesn't give us too much? And my experiment in that is the grips templating engine. It's a restrained templating engine syntax that gives you the power to do what you should be doing, and it restricts you from doing the things that I think you shouldn't be doing, like making method calls and doing arithmetic and other sort of business combinatorial logic. So you can check out that if that's at interesting in terms of the pain points that you've looked at. One other little note about grips is that another experiment that I'm working on right now is a CSS templating engine built on top of grips. Now, many of you are familiar with CSS preprocessors like Less and Sass and things like that, and with CSS preprocessors, we get the ability to sort of preprocess our CSS files, use variables and includes and other things like that, but it kind of, it's like it got halfway and then it just sort of stopped in terms of the evolution of that technology. We got pre-processors, and we just said, the only thing we need to innovate on is coming up with new, inventive syntax to stuff inside of our stylesheets. And I think we missed the boat, because I think that CSS templating, which treats it as a separate process that you're compiling a template from when you're rendering it, and it externalizes your data in the exact same way that we think about our HTML templates, we can think about our CSS as templates. So I'm experimenting with CSS templating, I think it's a lot more powerful than just CSS pre-processing, and I've built that as a module on top of grip. So if any of that's interesting, you can check out grips. And finally, I won't spend any time talking about this because at the end of today we'll talk about this, but asynquence is a promises-like Asynchronous flow control library that I wrote. it's really tiny, less than two K, to give you the power to express sort of promises-like syntax for Asynchonicity.
Speaker Introduction Part 2
I also do a lot of conference speaking, I won't belabor this too much, because I'm already talking too long about myself, I don't want to waste your time drowning on about myself, but I do want to highlight just one quick thing, These are some of the conference talks I've done over the last several years, and there's all kinds of video and slides and stuff online if you're interested, but I'll highlight just one of them, it's the browser versions are dead talk. And if this is at all interesting to you, this topic when I explain it, there is a video of that talk at BrowserVersionsAreDead.com. And I'd highly recommend that you go and take a brown bag lunch, take 45 minutes at lunch at work some day, sit down with your team and listen to that, and you can totally decide that you disagree with everything I say, but I hope that it will spark some good conversation. The premise of this talk is that our industry for the last, more than a decade now, has been guided by a set of lies and misconceptions that have been forced upon us by actors from outside of our industry. People like marketing departments, sales departments, CEOs, clients, people that don't understand how the platform works have been trying to dictate to us how the platform should work. And as professionals, I think it's time for us to start pushing back and asking some difficult questions, and saying, maybe that's not how we should be letting our platform work. The first of those questions, the first of those lies and misconceptions is that the browser version even matters. You hear all the time that people say, oh I'd love to do that, but I still have to quote unquote support IE six, or fill in the black with whatever particular browser version or browser vender that is your hated one at the moment. and I think that actually leads to this misconceptions that the browser version matters because in reality it's just an arbitrary marketing label attached to an arbitrary set of features. what we really should care about are the features themselves. We should be talking about what features we require, what features we support, and any other software discipline besides the web platform has embraced that for four decades or more. If you look at Linux programs that were from 30 years ago, they were feature-testing every single thing that they used. But that's sort of a relatively new mindset that we've adopted in the web, and I think we need to do more of that. You shouldn't rely on a production feature unless you're feature-testing for it. You shouldn't assume that because you're in IE seven you have some feature or not. The other bigger important lie that I think we need to attack is this idea that a site, or an application should be designed and built in such a way that it works, feels and behaves exactly the same in all browsers and all versions. Because again, this outside of our platform that's a ludicrous concept for you to suggest. I wrote a piece of software today and I expect it to work the same on a Linux server from 30 years ago. That's not the way the rest of the software discipline treats software, it's an evolving thing. We have, you know, different features get turned on and turned off and things, so I think we should build our sites and applications to be responsive to the environments that they run in. If you have a file upload feature built in to your social network, and you're running in a browser that doesn't have a file upload, instead of just blocking users and saying sorry, you cannot come into my social network because you're on a crappy browser, which is what a lot of people do, I think we should just simply hide the file upload feature. And it doesn't take a lot of extra effort to think about layering your applications to turn things on and off, provide fallbacks and so forth. So these are questions that I'm trying to push back on, and give you questions to ask and push back on those key players. Now, the reality is that 99% of the time when you push back and you tell your client, we don't want to build it that way, here's a better way to build it, they're going to tell you, that's all fine and good, but you still have to do it. So you're going to lose that battle 99% of the time, but I like to tell people that you will lose 100% of the battles that you never fight, and only 99% of the ones that you do fight. So these are questions that we need to, as professionals, we own this industry, and we own our platform, it's all of us, and we need to ask those challenging questions and push back so that we can, like I say, stop living 10 years in the past, and start living 10 years in the future. So, lastly about myself, as many of you probably know, I have been writing a series of books called You Don't Know JavaScript, the first title Scope and Closures is out in actual physical printed-book form, you can find that from O'Reilly, Amazon, all those other places. I'm writing them for free. Totally in the open, so if you go to YouDontKnowJS.com, redirects to the GitHub repo, they're completely open, released under the CC3 license, so I'm writing them in the open and then O'Reilly's been gracious enough to agree to professionally edit and publish those. The second title is already complete in terms of draft, the editing is in its final stages, and that should go to publish here in the next few weeks hopefully. And there's a plan for five titles in the series, and it's very aggressive, but we're hoping that all five titles should be out before the fall. So there's quite a bit of writing that I'm doing on this series. Most of the stuff that I'm going to teach you today comes from these books. The whole first section that we talk about about scope and hoisting and all, if you've read the book or if you know anything about the book, I'm basically , the books are sort of the written form of the trainings that I give. So it's all sort of tied together and these books are a good place to go and read further beyond what we teach today. That's it for stuff about myself. That was long and really boring. Let's get to more interesting stuff, let me make a couple of other recommendations. I don't get any benefit whatsoever, no kick-backs, but I do recommend both of these books as fantastic books. First one is High-Performance JavaScript by Nicholas Aikus. Now this one's a few years old, but Nicholas is writing, as I understand, an updated version of this book. So hopefully there'll be a second edition of that coming out, but it's a fantastic book to read. The other one's JavaScript Patterns. Really, really rigid, formal look at design patterns applied to JavaScript. I don't agree with everything that's written in these books, but they're fantastic books to read so I highly recommend you check them out. Really smart guys that wrote those.
JavaScript Resources
Some other stuff that I want to point out, some links that I want to direct you to, and these are all, by the way, you should all have your PDFs and you can follow along in the PDFs, but especially those to me that are here in person, but if you're following along in the PDFs, I have slide numbers up there and from time to time I'll make sure to, if I can remember, I'll make sure to say what slide we're on. so we're on slide seven right now. I give you that on purpose so that you can take notes against the slides, 'cause I'm going to present, there'll be times when I show a slide today and I talk for 45 minutes on one slide, and there's no possible way for me to put all of that information that I'm saying into slide form, so I highly recommend, as boring and lame as that sounds, I recommend you take notes against the slides, the slide numbers so that you can go back to them. But the other thing I'll say is, there'll be links that are provided in the PDF, there'll also be a bunch of places in the code where I show code snippets, and the code snippets that I show in these slides, they're just images, they're screenshots of color syntax highlighted code, which sucks, because nobody wants to retype all that code and actually, you know, shockingly have to write code, we don't want to write code, so there'll be links in the bottom left-hand corner of many of those slides that I'll point it out to you when we get to it in a few minutes, but there'll be a little link in the left-hand corner that's code me, and if you click on that link, it will pop you up to a web browser with that code there so that you can copy and paste it, it'll run that code so you can check it out and try it yourself. So that's a benefit of following along with the PDFs, both now and later. First link I want to point you to, just by show of hands, those of you who are here in person, how many of you have heard of Mozilla Developer Network? MDM? Okay, about three, four, so good. How many of you know that MDM is an open public wiki? Yeah, like one of you, one or two of you raised your hands. That's why I point this out. Because I think that's actually a hugely important fact that goes unknown. We just sort of think, well there're some team of people at Mozilla that goes and maintains all of that documentation. the truth is that it's owned by us, the web platform community. So there have been a number of times that I've been reading some documents for some, you know, documentation for some API feature, and it either says something incorrectly or it's worded weird, or there's not a good example, or there should be added information. you just sign in, create a free account, sign in, and edit it, just like you would with any wiki, like you would for with Wikipedia or whatever, and we can all contribute to the betterment of this documentation. So I highly recommend you do that. I know a number of people on the MDM team, they would be thrilled if we could get more people participating in that. So as a little piece of homework today, if there's something that I teach you about JavaScript or I mention some API or something like that, as a little piece of homework, I recommend that you go and do a search for that topic on MDM, and see what it has to say. If I talk about some API, you know, the substring string function or something, go look that up on MDM. Get familiar with that. Idiomatic JS looks like a JavaScript project. It's actually a write-up of idiomatic styles that are commonly accepted across the web platform, across the JavaScript community, and I don't agree with everything that's written there, but you never do, so I think it's just a great place to start. Probably 80% of it I think is great. If you do not have a style guide for your own projects or for your team if you work at a company, if you don't have one of those, this is a really, really solid place to start. Sit down at a brown bag lunch with your fellow employees, read through it over lunch and say, hey, we agree with that, I like that, but I don't agree with this and just come up with that. It's a great place to start, so check out Idiomatic JS.
ECMAScript Language Specification
How many of you have ever opened up and read any part of the JavaScript spec? Maybe we'll get a couple people from the chat rooms saying that they have, but my guess is I didn't see any hands go up. I read it every night before bed, it's great nighttime reading right before I go to sleep. I'm kidding. But actually becoming a lot more familiar with the spec lately from writing these books, because when I say something about JavaScript I got to make sure that I'm actually saying it accurately. So just real quickly what I'm going to do, if this link will work for me, I just want to take you real briefly through an experience that I just did a couple of days ago. I had a comment thread that was, that I started, I had read an article that somebody had written, great article, fantastic, smart guy from a company called Talbert, but I was reading this article and he made a statement about something about the way that the this keyword gets bound, and kind of stuck out at me as sort of feeling a bit inaccurate, or at least, you know, it's possible that I was misunderstanding it. But it felt a bit inaccurate, so I kind of started a comment thread and said, you know, I'm not really sure that's how it works, it seems like a misconception, and let's discuss it, and we kind of went back and forth a couple of times to clarify that he really felt this one way, and primarily felt this one way because of a quote that he had from John Resig's great book, Secrets of the JavaScript Ninja, which stated something about the way that this keyword was bound. And it should come as no surprise for any of you that know that I'm sort of a controversial person, I happen to disagree with John on that particular topic. I think the way that it's being stated is not quite correct, and so I have in my book, the second title of this series, explaining my explanation for how the this keyword gets bound, and it kind of, in one point at least, kind of contradicted that, and the question was sort of put to me, you know, well the spec says you know this, are you really sure that what you're saying is correct? So as an exercise, I said look, let me go through and create from the spec an argument that supports my position for how the this keyword, and I won't go through all the details, I just want to give you a sample of this. Now, the spec is difficult to read, there's no question about it. It's difficult unless you're really somebody that sort of, you know, like a wonk that really likes to think about these details. It's hard. I'm not saying that it's easy, but I do think that we should be, we should pay a lot more attention to what we're doing in the spec. So, I mean, what we're doing with JavaScript according to what the spec says. So let me make sure I'm on the right link. I think I am, yeah. All right, so why is my command F, find, not working? Of course, live I can't do it. Oh, there it is. That's weird. My browser's off the screen. There we go, okay. So where would be start if we were asking, 'cause if you search for the word this in the spec, you're obviously going to get several thousand examples of that, grammatically speaking. So where would we start in terms of how to find something in the spec, as sort of an exercise for what to do. So as you start to get a little bit familiar with the spec, and you understand how these things are laid out, you can start to get a little bit of experience, and the best place to start is with this table of contents, and kind of briefly scan through the table of contents and see if you can find anything that mentions the this keyword, and as we begin to scroll down, as we get a little bit closer, we're going to find, I'm not seeing it here, but we'll find here in just a moment that there's a place to start about, let me just cheat real quick and skip to the, oh there we go. So I was going to search for this keyword, 'cause that's what it says, so it's in section 11.1. Now this, okay, it evaluates to the this binding, so now we're going to have to go, this follow the rabbit trail. We're going to have to go and check out what the this binding is. So this starts to talk about execution contexts, and we see the this binding here, the value associated with it, okay, well that's not terribly helpful, let's see if we can keep going and find another example of the discussion about the this binding. And we're eventually going to get to this particular section of code. Now this is, when you're entering function code, what do you do? It says if the function code isn't strict, then set the this binding to this arg. So if you see right there where it says this arg, this arg means that there was an argument passed to that function execution that says what its this should be. So right here what we know is we're already at a layer of abstraction where, when the function starts to execute, the decision for what the this keyword has already been made, an it's been passed in. And that's something that we can gather just from understanding that, that there's a this arg that was passed in, but we know many of the times when we write our function calls, we don't pass that in. So there must be some mechanism that's doing it. So my next step would be then to say where does it talk about the this arg in the spec? And this is literally the process that I went through to try to come up with this. We can read here, by the way, in steps one and two, you can say that if it's in strict mode, it strictly uses whatever was passed in, but if it's not in strict mode, that's point two, and you pass in a null or defined, then it's, instead, defaults to the global object. So that's an interesting key because, well we'll talk about this later, but there's an interesting key that the default binding rule that we'll talk about, it's the fourth of four rules that we'll talk about later today, though the default binding rule says that if you're in strict mode, then this keyword ends up as undefined, but if you're in non-strict mode, it ends up as the global object. And right there, bam, in lines one and two we see the evidence for that exposition of that particular rule. So this is something where it doesn't actually, you know, the way I wrote it out in the book, you're not going to find that sort of thing word for word in the same terminology, but you can still understand something about the way our language works, and this is the official, you know, sort of place to come. So how would we, if we wanted to keep going down the rabbit trail, how can we look at? Well we know that when we are dealing with, you know function apply, and function call, we know there's always going to be a this arg that's being passed in, so we can see those sections being referenced there. But there's one other place that I want to call your attention to about the this arg. Actually, let me scroll up to the top and start my search from the top. You see all these other places where there's things in the code where you can supply a this arg manually. Now. Oh, it wasn't the this arg, sorry, what we want to do then is look for that this binding. Sorry, my searching skills are seeming to fail. I won't belabor this, but you can continue to look through this spec, and you can find out that there are other places in the spec where it will list these sort of bits and pieces of the rules. And you do have to kind of put five or six different sentences together to kind of come up with a coherent understanding of how the this keyword gets bound. That can be frustrating, but it also can be empowering. The fact that there isn't anything magical happening in the language that isn't spelled out here in the spec. That should be a confidence builder to you, that if there' ever something that's confusing, in addition to all of the places where you can try to read blog posts and try to read books, and try to understand what other people have to say, in addition to all of that stuff, you can also go to directly to the spec and see what the spec has to say. It takes some practice. I've been working at this a while, and I'm still just barely starting to understand some of the conventions and the words that they use. Takes a little bit, but I think that's part of being, having ownership over the web platform. So that's just a little kind of advocacy point to say I recommend as another kind of piece of homework that, at some point I'm going to teach you something today, like the this bindings, for instance, or the way, you know, lexical scope works. I'm going to teach you something today, I recommend as a piece of homework that you don't just take my word for it. Go back and look at the spec and see what the spec has to say. Just try your hand at searching through the spec and see if you can figure it out. So that's my advocacy about the EPC script spec, I think we should pay more attention to it as developers. Finally, it's important not only to know where the language is, but where the language is headed. This is one of several different links that are out there, we could probably come up with others, but there's a whole bunch of proposals for the future of the language, and that is ES6, which is impending upon us, it's coming very quickly, we'll talk a number of times about ES6 today, but there's also even ES7 and beyond stuff that's being discussed. Things like macros which are likely going to come in the ES7-ish time range. Things like that. So there's a whole bunch of stuff that's being discussed about the future of the language, some of it sounds really cool like macros, and some of it sounds really terrible like operator overloading, but they're being discussed as futures of language. So I don't think it's a good idea for us as a development community to just sort of turn a blind eye to that, and wait five years until it's already been decided, I think we need to participate in that process now. The TC39 community's been incredibly open about keeping all that stuff out, they published notes from their bi-monthly meetings. So I recommend you kind of take a look at what the spec is doing.
Course Plan
So I'm going to give you, this is not the official title, but this is kind of the unofficial title for today's, this is a two-day workshop, this is the unofficial title, because this is what I give when I give this one-day talk as a standalone, I call it the What you need to know parts. Advanced JavaScript, the What you need to know parts, and I need to explain to you what my practice is going to be. You should already get a flavor from that just from our discussion of looking at the spec, but I want to understand, I want you to understand what you should be expecting from today. So first of all, I call it Advanced JavaScript. Does that mean that I expected you to be an advanced Javascripter before walking in here, or before joining online? No. That's not what I expect. What I do kind of recommend is that you're taking this course with at least maybe one to possibly two years of experience with JavaScript. And that's not a requirement, that's just a recommendation that you at least be familiar with the language. So we could call it sort of somewhere between beginner and intermediate in terms of your experience, kind of your base experience. I'm not going to teach you how four loops work, I'm going to expect that you understand stuff like that. But I am going to take things which you might consider to be basics, things like lexical scope, which you just sort of, maybe you never even heard it called that, but you just sort of understand kind of intuitively. We're going to take that stuff and break it down into extremely deep detail. I'm going to give you like compiler terminology here in a few minutes, and that may feel a little uncomfortable, because some of us aren't quite like me, I write compilers for fun, but not everybody does that, so understanding that kind of deep terminology and concepts can be difficult. And so, when I say advanced JavaScript, I really, it's kind of like the advanced basics. We're going to take the basic things that I think are requirements for you to understand before you can be an advanced Javascripter. There's a whole bunch of stuff that you could spend 10 or more years in this industry writing JavaScript and never actually understand. And there's a lot of people that will attest to that. I've written JavaScript for a decade and I didn't understand how closures work. It's just a fact, because Javascript's so approachable, it's so easy to get up and going, and you can spend your entire career never being forced to actually learn it. I'm going to force you today to actually learn how that stuff really works. So some people would define advanced JavaScript as broad as possible, let's look at every possible acronym and framework and you know, hot pattern of the day, let's talk about all these possible things and there's lots of great courses, you know, Mark's got lots of great courses and there's lots of other great content out there. You know, infinite numbers of blogs and books that talk about this sort of stuff. That's not what today is. Today is going to be very narrow scope of what we're going to discuss, but we're going to go extremely deep with it. We're going to dig our teeth deep into this stuff. So that's what I mean by advanced. And when I say the What you need to know parts, obviously I'm making a play off of Crockford's The Good Parts, but when I say the What you need to know Parts, I'm going to explain to you, like when we talk about the this keyword, or when we talk about the definition of what closure means, I'm going to explain to you in what I hope is more understandable terms than just quoting to you the spec. I'm not going to just show you a bunch of screenshots of what the spec says, although I think it's important to be aware of what the spec says so that you're not saying things incorrectly, my focus here is to give you practical takeaways on things. So this is the What you need to know definitions for these things, rather than the necessarily the acronymic ones. There'll be people that disagree with me and say no, no, no, that's not a type, or no, no, no, that's not really accurate about closures. And my answer to that is to just shrug and say, oh well. you know, I'm not interested in being academically formal, I'm more interested in giving us practical understanding. Okay, so without any further ado, this is going to be our first discussion point. We're going to spend a good portion of the morning talking about scope and closures. So we're going to start by talking about nested scope, we're going to move into a discussion of hoisting. You may or may not have ever heard of what hoisting is. And I'm going to do something kind of interesting, because if you understand anything about these mechanisms, it should seem strange to you that third item on the list. When I talk about the this keyword. Sort of injected right in the middle of a discussion about lexical closures. Maybe that seems weird, maybe it doesn't. If it doesn't seem weird to you, I hope it does seem weird to you by the time we get there, because the point is actually that these are completely opposite mechanisms. So the reason I stick it right there in the middle is to make it really obvious the contrast, the difference between them. So this is an unusual approach. In the books, I didn't deal with the this keyword inside of the scope and closures 'cause my editor was like, no that's too weird. But when I'm doing training I can do whatever I want, and I think it's better to talk about it there so that I can contrast it. So that's intentional that it's kind of weird, but then we'll jump right back into a discussion of closure. And I should also say, there'll be here and today one, there'll be a fair amount of lecturing, I'm going to a bunch of talking and things like that, but there's also, as you know, there are five exercises. Each one of those is designed to be anywhere from, you know, seven or eight minutes up to like 15 minutes of just free time that you're working on something, or I give you the exercise, I give you some time to work on it, I shut up for a little bit, and then I come back and kind of give you a guided solution tour, if you will, kind of how I would approach things. There's no right answer to any of this stuff, but I do provide, in each one of those exercises, a fixed version of the files that gives you my example how I would have done it. So at a later time you can come back and say, okay well how did Kyle do it, but that doesn't necessarily mean that's the only way to do it. So there will be exercises for you to do. Now, if we can transfer that to what we're going to deal with tomorrow, there's comparatively a lot less lecture tomorrow and a whole bunch of just like hacking at the code terminal. So there's very few slides, and we spend most of our time just kind of live coding. Tomorrow. So if you're really looking for that code and if you feel like I'm lecturing and I'm too much boring, just hold off until tomorrow. If you like the lecture stuff, there'll be plenty of that today. The goal for today is to give you a really, really solid foundation of understanding about the core mechanisms that JavaScript relies upon so that when we talk about scope, I mean, when we talk about something inside of node JS, and I just assume that you understand what lexical scope means, when I talk about a module hiding the scope, I'm going to assume that you understand what that means, and I can't assume that today. Even if I looked at some of the responses from the pre-event surveys, some people felt really confident with the stuff, and other people are coming in with not quite so much confidence. So the goal is that everybody walks away from today with that confidence so that when we talk about node tomorrow, there aren't questions about those core mechanisms, we can really focus on the thing. It's kind of one of those hidden secrets about the node world. A lot of people tend to think that if you talk about a scale of one to five, like my understanding of JavaScript is a two out of five, then my understanding of node is a two out of five, and in reality they're actually kind of skewed. You can have an understanding three in JavaScript out of five, and you can still be at a one level understanding in node, because node requires you to understand a whole bunch more of the language than you've ever been forced to understand really before. Where you get yourself into trouble. So they're kind of skewed, and that's why we set this up as a two-day workshop, so that we can make sure that we fully understand JavaScript before we talk about node.
Scope
Scope and the JavaScript Compiler
Well, let's get in to a discussion of scope of closures. Your first, what-you-need-to-know definition, scope, where to look for things? Now you should rightly ask yourself a question on that first slide, what are we looking for? Okay, well, what we're looking are going to be the variables that we reference. Anytime you reference a variable like my object and use an identifier name, somebody needs to go and do a look up to find out where is that variable, where does he exist, where does he declared? And as we'll get to, there's lots of different places, lots of different scopes that, that can exist. So that's the first question, is what are we looking for, what are those things? Well, we're looking for variables, we're looking for lexical identifiers. The other question is, who's doing the looking? And that's an even more important question, who's doing the looking? And this is where we're going to start to maybe push your comfort zone a little bit right off the bat, because I'm going to start to introduce some compiler terminology to you. Because the first misconception that I want to completely dispel is that JavaScript is not, or it is stated that JavaScript is not a compile language, that JavaScript is dynamic, it's an interpreted language, and that is just a false statement. So for those of you that have been under the impression that JavaScript isn't in compile, that there isn't a compiler involved, let me just dispel that myth for you, JavaScript is a compile language. Now it's not quite the same as how we compile our C++ or we compile our Java or things like that. There are certainly some differences in the way we deal with it, and the primary difference is that we don't distribute, that is, we don't send out the binary compiled form of our programs like we do with C++. We compile it into an exe and then we send it out to people, or you know, Java, we compile it into byte code and we send that out to the Java, JVM. We don't do that with JavaScript. We send the original source code program. So in a sense, it is compiled, but it's compiled every single time that it's run. But that doesn't mean it's not compiled. Now what do I mean by an interpreter? So the difference between a compiled language and an interpreted language is let me give you a comparison. If any of you have ever than bash scripting, Bash is an interpreted language, which means that when it is running line three, it has absolutely no idea what to expect on line four. It hasn't even looked at line four yet. It's not there yet. It's dealing with line three. So an interpreter literally goes from top to bottom. Now there's obviously some looping mechanisms and other things that interpreters can do through go to and things like that, but interpreted languages go top to bottom just line at a time. In JavaScript, however, and in other compiled languages, a compiler does an initial pass through the code to compile that code, and it does at least one more pass through the code, and then that final pass is when it's going to do it's execution. So it has looked at line four before it starts to run line three, just sort of in general, okay? So as we start to talk about the compiler, we have to understand that the compiler is going to look for these blocks of scope. And it's said that JavaScript has function scope, that the blocks of scope that JavaScript has are functions, and I put that asterisk there because as we get to talking a little bit later in this section, we'll see that, that's not always going to be the case. But at the moment, in the current version, the current standard version of the language that you have, the smallest atomic unit of scope that we have in the language is the function. So here's one of those cases where I'm going to put up a slide, and I'm going to talk about this slide for quite a while. We might be on this slide for 20 or 30 minutes. And you're looking at that like, (sighs) it's crazy, this is smaller than a code I would complete, possibly do it. I need to start introducing some of that compiler terminology to you because you'd understand that the compiler is going to look at this code a bit differently than you have probably trained yourself to look at this code. And I think we need to think a little bit more like the JavaScript engine, so we can understand exactly why it does what it does and how does it. So the first thing that I'll illustrate to you is that there's a lot of complexity that I'm going to gloss and hand wave over. Compilation is all kinds of things like tokenizing and all that stuff. We're going to completely hand wave and gloss over all of that stuff. But there's one important part of the compiler phase that's really important to our discussion, and that is finding declarations of variables and functions and putting them into their appropriate scope slots. That's the pass that we're going to think about. So what we need to do is think about this code. We'll get passed through once by the compiler first, and then a few microseconds later, it's going to get a second pass through. After it's been compiled, it's going to get a second pass through where it's been executed, okay? So that's conceptually how we're going to need to think about this code. The first thing that you'll see there right on line one, you'll see what everybody will probably commonly recognize as a variable declaration. Var foo, we see the var keyword. It means variable declaration. We see and identify our name, foo. We see an initialization of that variable to some value. In this case, it's an immediate value, a string value. Most of you, I'm willing to bet, would think of that as a single JavaScript statement. And grammatically speaking, it is true that, that is a single JavaScript statement. If you go to the spec and look at the grammar, that's a variable declaration with an initializer. It's just a single statement, we see a single semicolon. However, that's not really how JavaScript is going to process it when it needs to execute this code, and that's the difference, that's the nuance that we need to learn to understand our code better. We need to understand that rather than this being thought of as one statement, this actually should be treated as two entirely separate operations. There is a declaration operation, which we could map to saying is the var foo part; and there is an initialization operation, which is the foo equals bar part. And those two operations actually happen at totally separate times. They might only be a couple of microseconds apart, but they don't happen at the same time. And in fact, it's not even the same mechanism within the engine that's dealing with them, okay? And that's the key thing that we need to understand. So we need to start to look at our code with slightly different eyes than we might be used to. We might be used to thinking about that as a single statement. In fact, we need to think about it as two statements so that the compiler is going to do a single pass, or you know, the pass that we care about is going to pass through, looking for all of the variable declarations in all the places that it can find them. And it's not just the var declarations, but it's also these function declarations. Those are also declarations that we're going to look through. So what we're going to do is going to anthropomorphize, it's a fancy way of saying we're going to treat as a human being, that we can have a conversation with, the JavaScript engine and the various parts of the JavaScript engine. And I'm going to teach you a slightly formal way of talking to that engine, and I'm going to, it's going to feel weird why I keep telling you to say it this way, but you're going to get some practice over this in the next slide, and it'll feel a little bit more natural over the next few minutes. We look at these declarations and we say, okay, the JavaScript compiler is going to go through and find declarations. So the first line, the compiler is going to come through and say, ah, I see a variable declaration for an identifier called foo. Which current scope am I in? And the answer to that question is you're in the global scope right now as we see it in this the code. Okay, I want to register the foo identifier into my current scope, which happens to be the global scope. Now I move on. I completely ignore this thing because that's not something I need to deal with. I move on, where's my next declaration? Okay, my next declaration is on line three. I see a function declaration with an identifier named bar. And it's differentiated from line one where we didn't care about the assignment of the value. Here, we are actually going to care about the value, we're going to care that it is actually a function that goes along with this declaration. Those really aren't kind of separated. They're treated as one sort of operation, at least in our concept here. So we're going to register the function bar into the same scope. We're currently in that scope of bar. Now it's at this point that we need to talk about a nuance of the way JavaScript works because we're talking conceptually about JavaScript compilation in the most basic and naive of terms. If you were a computer science student and you were told to sort of write a compiler for the JavaScript language, I took a compilers class, compiler theory class, I got to do something like that, if you were told to write a compiler, you would just sort of do this top-down approach. You just sort of scan through the code and when you recognize the declaration, you'd register it to whichever particular scope you were in. The JavaScript compilers of today are fantastically more complex than that naive computer science student implementation would be. So if you've ever heard of things like JIT, J-I-T, that stands for just in time compilation, the idea behind just in time compilation would say, this function bar here, we don't see it being called. So rather than compiling the contents of the function bar, we'll just skip over it. And we'll come back to it later, we'll compile the function bar whenever we are forced to because it's been asked to be executed. So we'll defer the compilation and we'll compile it just in time. Even more complex than that is that many of these engines are doing, kind of started in the Firefox world where they were tracing the performance of these things, but there's this idea that you can hot-swap the compilation of a function. So when they compile a function in JavaScript, because of all the differences in the way that types are not enforced as strongly and statically as they are in other languages, in a sense, the compiler has to kind of make a best guess as to how you're going to use a function. It can kind of do some inferences about types and other fancy things like that, but it has to make essentially a guess as to how you're doing this, opposed to the C++ compiler, it knows exactly how that function is going to work. It knows all the inputs and all the outputs and the types and everything so, oops, I skipped back... The C++ compiler has to do, it has enough time to get it right the first time, if you will. But the JavaScript engine, it doesn't have enough time, and it doesn't have enough information so it has to make a best guess. And so many of the engines will make a guess, but they'll instrument that initial guess, and they'll let the function run maybe, say, a couple of dozen times or something like that. They'll monitor how well the guess was. Did we guess correctly? Is it being used in the way that we think it is? If the guess was incorrect, if it turns out that they didn't do a very good job of guessing, they'll throw away the compilation and recompile the function and hot-swap in those bits directly. So there's all kinds of, and there's way more even, I'm totally glossing over a bunch of (mumbles). So there's way more to it than that. We're going to be just the naive, top-down compiler, okay? So even though the real ones might not compile bar now, we're going to compile bar right now, just as if we're being a naive, top-down compiler.
Compiling Function Scope
So now that we see that we're in a function, we know that's a new unit of scope, so we're going to sort of recursively descend into that function and we're going to compile the contents of that function. It's not a terribly interesting function obviously at this point, but we're going to look for declarations. Where is the next declaration that it's going to find? Foo? Tell me line numbers. Four. Line four, it's going to find a variable declaration for foo. Now what scope is it in? The bar? It's the scope of bar. So it's going to say, hey, scope of bar, I have a new declaration to declare. His identifier name is foo. So we're starting to have this conversation. This is the compiler having a conversation with the scope portion of the engine, the scope manager, okay? Do I have any more declarations in my current scope of bar? No, okay? We're done with the function bar. We've compiled the function bar. Let's move on. We're back to our global scope, so we've popped ourselves back out to the global scope. Where's the next declaration that we find? Seven. Line seven we find a function called baz. Okay, let's declare hey, global scope, I've got a declaration for an identifier called baz, he happens to be a function declaration. Go ahead and add him to your declaration list for the global scope. Now let's recursively descend into that function baz and compile him. Where's the next declaration that I find? Argument? Ah, see there's a tricky little one. Not as many people will catch that. There's a declaration, an implicit one, because we have a named parameter called foo. There's a named parameter, and that named parameter will be treated like a local variable. It's kind of like there was a var foo right here. So we can assign to that variable, we can read the initial value that might've been passed into it. We can treat it in all other ways like it's a regular local variable. So there's a declaration that we need to declare. Which scope are we in? Baz. The scope of baz. So hey, baz, hey scope of baz, I've got a declaration for a variable, and he's called foo. I need you to register him there. And the scopes says, okay, great, we're done. So we continue on with that function. Do we see any more declarations in that function? The answer is no, we don't see any more declarations. We're now done compiling our program for the purposes of scope resolution, okay? Obviously, there was a whole bunch of other compiling that happened, that we just skipped over, but we're done compiling our code for the purposes of scope resolution. Now it's a couple of microseconds later, and you don't see in this code somewhere where they're being executed, but let's assume that this code is being executed somewhere. Let's assume that somewhere else in our program, bar is going to get called, baz is going to get called. Let's execute this particular line of code. We're a couple of microseconds later, and let's execute this whole line of code. So how is line one going to be executed? The first thing you need to understand is there's no more var any more because we handled that in the compilation face so he doesn't exist in the execution phase. What's left of line one then? (audience muttering) The foo equals bar part, the second operation. That's what's left for our execution phase. The foo equals var part. The var part is not left for our-- execution phase. It doesn't exist. If you do, var foo, var foo, var foo a hundred times in a row. Guess what happens to the other 99 of them after the first one? (audience muttering) They're ignored because they don't actually exist during the execution phase. A lot of people think, well, if I encounter a var halfway through my program, it's going to, you know, at that moment, it's going to create a whole new variable out of thin air; and that's not true because that was all handled during the compilation phase ahead of time. This will all flow into our discussions of hoisting and things like that when we come back to those later this morning. Okay, so let's execute line one, and here is where I need to introduce to you some new compiler terminology. The terminology I'm going to introduce is the idea of an LHS and an RHS. LHS stands for the left-hand side. Anybody have a guess for what RHS stands for? (audience chuckles) You guys are smart, and everybody's had their coffee, everybody's well awake. LHS stands for left-hand side, RHS stands for right-hand side. Of what? That's the important question. Of an assignment. In our language, the assignment is the equals operator. So what's on my left-hand side of the equals operator? Variable name? Variable name foo. So foo is said to be an LHS reference, okay, all right? Don't get scared about our compiler terminology. I promise you, it's not going to be as hard as it may seem at first. Foo is our LHS reference, okay? What's the RHS? String. It's the immediate value, the string value. So it's not a reference. So for the purposes of scope, we don't need to worry about RHS this year. But there is an LHS and RHS. Now the terms come from the transliterative term. Left-inside side and right-hand side come from the initial looking at this equal sign and saying there's a left and a right. But there are other ways for assignments to occur, which don't have an equal sign. And there's still an LHS and an RHS even though we don't see a visible left hand inside and a right hand side. So you do need to actually broaden your understanding of LHS and RHS from their transliterative left hand side, right hand side meaning to, the LHS is the target and the RHS is the source, okay? The source of our assignment, the source value, is the right hand side, this immediate value. The target is where we're going to put it, foo, okay? And there are other places, like when you pass in a variable to a function call, it's not obvious that there's an equal sign happening there, but there's still an assignment that's occurring; and there's a source and there's a target, okay? And it's important to keep LHS and RHS distinct in your mind. I'm going to drill that into you. So if it feels weird, I promise there's a reason why, because they actually behave differently with respect to scope, okay? So it's really important. We have a question? Hey, Kyle, we have an online question. Can I clarify what exactly is a definition when looking at that code? Definition. Okay. Not sure where the terminology definition is coming from. The more common terminology would be declaration. But maybe somebody in the chat could expound upon what they mean by definition. See what he says here. There's a couple different ways that I can interpret that, so rather than assuming I know, let's see if we can get some clarification. All right, so we've executed or we've started to execute line one. The first question that we need to then ask is when I have an LHS that is a reference to a variable, I need to ask where that variable exists. So I need to ask a question of my scope manager. And that question that I'm going to ask is essentially hey, scope, which I have my current scope, which happens to be the global scope, hey global scope, I have an LHS reference for a variable called foo. Have you ever heard of him? What is the scope manager going to respond to us? Yes, I've heard of him. It is the variable foo. We aren't dealing with the right-hand side right now, we're just dealing with the LHS side of it. We're asking our scope manager for a reference to the variable that we want to assign to. We may not have found it in our current scope. We might have had to go elsewhere, which we'll see in a little bit. But right now, we found it immediately. So the answer to that initial question, hey scope, hey global scope, I've got an LHS reference for a variable called foo. Ever heard of him? The answer is yes, I've heard of him because you declared him just a couple of microseconds ago. Is everybody with me on that? So I'm going to give you a reference back to the variable that you declared, and I'm going to allow you to perform the operation. Now if the right hand side was more complicated than just an immediate value, if there was a variable there, then we would need to do another lookup. We'd need to say, hey, global scope, I've got a variable called bar for instance, or something, but we don't. We don't need to do any more lookups because we did our lookup for the variable foo. Did we get a clarification, Will, on the question? No, he's not responded yet. Function definition, I think. Okay, we just got it. Function definition? So function definition, again, the more common way to say that, hopefully I'm answering your question there online, the more common way to say that is function declaration rather than function definition. But a function declaration is where we see the function keyword followed by a name, followed by a block of code. So that's a function declaration. Now we'll clarify, there's a different way of making functions, and that's called function expressions, and we'll clarify that in a few slides. But a function declaration as we see it, is exactly what you see here, where you see function keyword with the name after it like that. An argument list and a body. So hopefully that answered the question that was being asked. If not, clarify again. Okay, so we don't need to do any lookups for the right-hand side because we have an immediate value. We've already looked up the left-hand side so we know where it's going. So we can just perform that operation. We can just take the value, copy it directly into the location. And we're done executing line one. Every body pat yourselves in the back. You've just done your first JavaScript engine operation.
Execution of Function Code
Now we don't see the executions of the declarations of function bar and function baz anymore. As a matter of fact, from an execution perspective, lines three through 10 don't exist anymore because they've been declared elsewhere. But let's pretend that bar is going to get called. So let's execute the function bar. We're inside of the scope of bar now, and we need to execute line four. Remember, the var doesn't exist anymore. So how are we going to execute line four? Everybody tell me, what question needs to be asked, and what is that going to sound like? Ask the scope for function bar manager what foo is. Hey scope of bar, I have a what kind of reference? (mumbles) variables. It is in LHS or in RHS? LHS. I have an LHS reference for a variable called? Foo. Foo, ever heard of him? What's the answer going to be back from the scope of bar? (audience member muttering) Yup, you declared him just a little while ago when we compiled the function. Here you go. So it's going to hand us back a reference. Now we go to the right-hand side again, the right-hand side is an immediate value. I wanted to make this code a little simpler so we got an immediate value, we can just copy it and we can execute that operation, that assignment operation from line four. Everybody with me so far? Okay, feel free to ask questions, feel free to stop. This is an interactive class, you don't want to just hear me drone on all day. I want you to be able to-- Will it not use local scope or something? Say that again? The foo, will it not result in a local scope or something? Will it not say, hey, I have no good scope for foo? That's exactly what just happened. It might have been subtle, but our conversation said hey scope of bar, so we're asking the local scope of bar, do you have a variable called foo? We always ask our local scope first before we go elsewhere. And we'll get to that in just a minute, okay? All right, so now let's execute the function baz. And again, for the purposes of our discussion, we don't see the baz being executed. So let's ignore any assignment that might've happened to the foo ahead of time. Let's just execute baz as it stands. How are we going to execute line eight? Hey scope of baz, do you have an identifier named foo? What kind of a reference do I have-- Left handed. I got an LHS reference. Again, I keep hammering on that. That sounds like an irrelevant point, but we're going to see why it's actually really relevant. I have an LHS reference for a variable called? Foo. Ever heard of him? What's the answer going to be? It's in my definition. It's in my definition because I had a parameter named that, so I have a local variable called foo that I can reference. So it hands us back a reference to that so that we can assign a value to it. Everybody with me? We then assign bam into that foo. Now when we assign it to do foo, are we assigning to that guy or to that guy? No, obviously not because the guy that we got returned, we asked our local scope first, and that's the guy we got returned. Here's where things get interesting, and here's where people start to get pissed off at JavaScript. Let's execute line nine. How is line nine going to execute? Badly. (chuckles) Badly. Good answer. He'll ask baz. Hey scope of baz, I have an? Bam. I have an LHS reference for a variable called? Bam. Ever heard of him? What's the answer going to be? Nope. Anybody ever played the... What was that? Are you in strict mode? We are not in strict mode. We see no strict modes. So the answer is going to be, never heard of him. Anybody ever heard of the card game Go Fish? Sometimes I give this class in cultures where they don't know the card game, so it misses this reference. The card game, Go Fish, where I got some eights in my hand and ask for eights and I have to give them to you, but if you ask for nines, what do I say if I don't have nines in my hand? I say go fish. So it's kind of like that. We ask the function baz, hey scope of baz, ever heard of a variable called bam because I got an LHS reference for him; and the answer is go fish. I don't got it, never heard of him, go fish. So where do we go? Well, we go out one level of scope. So we begin to think about these scopes as being nested inside of each other, and we'll get to nested scopes a little bit more formally. But what we see here is because I cannot fulfill that reference for bam inside of my local scope, the next place that I go is to my global scope in this case. It could've been a surrounding function, could've been 15 levels deep. It doesn't matter. But I would go to the next outer and then the outer and the next outer. Of course, once I get to the global, it's either going to find it or not, but I have nowhere else to go beyond the global. But we're at the global, so we're going to then say, hey global scope, I've got an LHS reference for a variable called bam, ever heard of him? And what's the answer from the global scope going to be? Just did? The answer's going to be: yes, I just created him for you. And that's where people get really pissed off because we're not in strict mode and we would expect for the global scope to say no, never heard of him. But unfortunately, it will go ahead and create one for us because we had an LHS reference. And here's why that's important. (mumbles) RHS reference, it would've been different. But because we have an LHS reference and we get to the global scope and we're in non-strict mode, he's going to say, oh, I tried to be a helpful guy. I went ahead and created a bam for you in the global scope, not in your local scope but in the global scope. And so here you go and you hand it back. So when we make this assignment, are we assigning to a local variable or to a global variable? Global. The global variable, the bam. That's where we get this idea of leakage of global variables. That's how it happened, because we didn't find it in our local scope. We stepped out to the outer scope, and because we're in non-strict mode, he responded back and he said I went ahead and created one. Now had we been in strict mode, which I recommend you write your code in from now on, by the way; had we been in strict mode, the answer would've been, nope, never heard of him. Now if you get to the global scope and you get back an answer that says nope, never heard of him, that's an error condition because you're trying to assign to somebody that's not been declared. This is an important key difference, and we're going to come back to this a couple of times today throughout the rest of the morning and this afternoon. The difference between something being declared or not. If it was declared, there's going to be a var somewhere or a function somewhere. That's required to make something declared. If you do not see a declaration somewhere, it is in the state that we would call undeclared, which means basically that we were unable to fulfill a request to find that reference in any of the scopes that we had access to. So an undeclared variable means we were unable to find an LHS, a proper LHS reference for it in any of the scopes that we have access to. Does everybody follow that? Okay, now there's another word in JavaScript, which is undefined. And I'm sure all of you have heard undefined. A lot of people think that the word undeclared and the word undefined are synonyms of each other; that undefined means the same thing, and that's totally false. The word undefined and the word undeclared are very, very different from each other. Undeclared is what it should've been called when there's no present declaration for the variable in any of the scopes that we have access to. Undefined means he was declared, but he has this special empty value that we mistakenly called undefined. Shouldn't have been called undefined. Should have been called something else entirely. But it really is more akin to the word uninitialized. The undefined is a proper value, it's not the absence of a value. It is an actual value. It's kind of like in physics and in space, like a vacuum. There cannot be a vacuum where there's no value. So whenever you remove everything else, the undefined value immediately injects himself. He's a proper value and he exists, but that does not mean undeclared. So keep undefined and undeclared distinct in your minds. Any questions so far? I told you I promise we'd spend 20 or 30 minutes on this one slide. Any question so far about this idea of asking our scope engine about LHS references? Okay. Go ahead. I'll get you. When you said undefined, is there any actual value? Or what exactly is told by the companion for that? There is actually a proper value called undefined. If you look it up in the spec, undefined is an actual value. It's a type that exist that has one value in it. There is an undefined. I'll get to you in just one sec, Will, because I have this question over here. I was just wondering if you could speak to some of the nuances in like, IE8, for scoping, if there's anything? Nuances in IE8. Well, you might have to be a little bit more specific because there's got to be-- I've never really fully understood it, but I know that window doesn't always equal bubble in IE8, and I was just wondering if you had any... Hmmm. So I don't really have a good example that I can explain of a condition where window would not be global. If you could come up with a concrete example, I could kind of look at it but I don't-- Sure, so they changed all of their script loaders, and now they explicitly declare window dot gac or IE8. Who is this? Google for analytics. So originally, they just called it GBUs, EAC, large EAC. But I guess there's like some problem with IE8 that multiple scripts don't use the same scope. So if you declare a var in one script and then you declare it later, it'll actually override. It does something weird with the window or bubble scope, and that's just kind of what my question-- We might have to dig into that like over lunch break. I'm not familiar with that particularly scenario to really... That sounds like an awful bug if that's true. Yeah, Will? All right, mine wasn't a question so much as just a comment. If everyone could speak up for their questions, sometimes you can't hear it on the stream, otherwise Kyle-- I'll try to repeat the question, yeah. Yeah, if you would repeat questions that sound quiet, that would be-- Perfect, thanks, yeah. My question is if you had declared foo in function baz. Uh-uh, you mean I've done a var foo here? Yup, the argument that it's passed in would be the var foo that was declared on line one or... So the question is if I had, had on line eight, if it had also said var foo, so I've got a variable declaration for foo as a parameter name, and then I tried to essentially sort of re-declared is what a lot of people would think that was doing, what would happen. Is that your question? Right. Okay. So the first question to answer, we got to go back to the compiler phase. We haven't dealt with multiple declarations, but the first thing that would happen when we were compiling function baz is that we would declare the variable foo by virtue of the named parameter, foo. So we would declare the foo. The next time we run across a var foo anywhere in that function, it's going to say, hey, scope of foo, I have a declaration for a foo. And the scope is going to respond back, no big deal, I've already got it because I've already declared it. Now that's for variable declarations. There will be a subtle nuance that function declarations are able to override each other. But for variable declarations, it just essentially would've ignored that subsequent var had we put it there on line eight. That answer your question? Yes, so then within that function, foo will override var with bam. On line seven and a half, foo might have a value that was passed into him. For our purposes, we're ignoring whatever value was passed into him or overriding it. So it is the same variable we're overriding. But we could have, on line seven and a half, we could have console logged out the initial value. And if we passed it in as the number 42, it would have that value before it gets to line eight.
Scope and Execution Example
Before we broke, we were talking, we kind of introduced this idea of the scope mechanism and how the scope gets registered in the compile phase, how we look up LHS references. This example is going to more firmly concrete some of those ideas and show us some of the differences there. We are going to pick up our pace a little bit because we want to make sure we get to a bunch of great stuff today. But the questions have been great. I don't mean at all to discourage questions, please keep asking questions both here in person and as well, there on the video stream. Okay, so now you should be familiar with that terminology of LHS and RHS. So I'm going to require you guys now to respond, you guys that are here in person. Tell me what is going to happen when we try to compile this program. What is the first step when we try to compile this program? Hey scope, do you know about foo? Which scope are we talking about? We got to be clear. Global scope. Global scope? We're compiling, we're not executing yet. So what is the compiling phase going to do with line one? I will now expect something to be assigned to foo, or I now know of foo. Okay, that's one way of saying it. A slightly more formal way of saying it would be to say hey, global scope, I have a declaration for a variable called foo, okay? So I'm going to declare a variable foo, and the scope would respond back, got it, I've got him registered in the scope now, you can move on, okay? But we're going to ignore the right-hand side because there are no declarations there. Where's the next declaration that the compiler is going to worry about? Line three. Line three, the function bar. So we're going to say, hey, global scope, I have a function called bar, and I want to register him in the global scope, okay? And not only the name, but also the function. In this case, it's a function declaration. So line three is going to register that function. Now we recognize that it's a function so we want to go ahead and recursively descent in and compile that function bar. So now we're inside of the scope of bar, how are we going to compile the scope of bar? Hey, scope of bar, I'd like to declare a variable named foo? Exactly, I have a declaration for a variable called foo. That's from line four. Okay, great, line four has been declared. Moving on, what's next? Scope of bar, I have a declaration for a function baz. Exactly. Here's the declaration baz, the scope of bar responds back. Good, I got him registered. Now we recognize it's a function, we recursively descent in. How are we going to compile the function baz? Let's see the declaration of foo on line six. See a named parameter for foo, which is an implicit declaration. So it will say, hey scope of baz, I have a declaration, he's a named parameter but I have a declaration for an identifier called foo, okay? Anymore compilations that's going to occur, anymore declarations anywhere? Does everybody feel confident that we've know compiled our program; or at least for the purposes of scope discussion? Okay? Now it's a couple of microseconds later, let's go ahead and execute. What we know is that line one is not going to have a var anymore, so let's execute line one as an operation. How is line one going to be executed by the engine? What's the conversation going to look like? I have a left-hand side identifier-- Which scope are we talking to? We got to be-- Global scope. Hey global scope, I have a? Left-hand side. I have an LHS reference for a variable called? Foo. Ever heard of him? What's the global scope going to respond? Yes. Yes, I have, here you go, and he's going to give us a reference back to that variable. So then we proceed to make our assignment to it because we got an immediate value, so we make that assignment to foo. Everybody feel comfortable with line one? Moving on, lines three through 11 don't exist anymore because they were compiled away. So we're moving on to line 13, that's going to be our next execution. How is line 13 going to execute? Global scope, do you have a reference to-- What kind of a reference? A function reference. It's not quite what he's going to say. It's got to be an LHS or an RHS. LHS? (audience members muttering) Yeah, so it is going to be an RHS, but why? And here's the key distinction, this is kind of a weird way to define it, but it's kind of your best, not exactly. Here's the way to explain it. The reason it's an RHS is because it's not an LHS, okay? (audience laughing) I know it sounds silly, but there's not an assignment going on with line 13. The bar reference is not being assigned to, it's being used. So because it's not an LHS, it's an RHS. So on line 13 we say, hey, global scope, I have an RHS reference for a variable called bar. Now here's why it's important, because the RHS reference is going to behave differently, depending upon declared and not declared. So we'll get to that in just a moment. But I have an RHS reference for a variable called bar. What's the global scope going to respond to? What's he going to say? Yeah I do, here you go, here's a reference to that variable. So I can go ahead and retrieve that value. Now I go and retrieve that value, and what is that value? Line three, it was a function object okay? So I get back a function object, now I see this open close parentheses on line 13, and good news, I don't have to sweat it because I got a function back and I'm going to attempt to execute the function. So line 13 will attempt to execute the function that we just retrieved from the bar variable. Everybody feel comfortable with that? Does the scope turn this into an apply and assign it with this? Like is that happening behind the scenes? No, if you look at the way the spec is written, there are different rules for the way a function is called when it's called like it called on line 13 versus when it's called with a dot caller apply. And when we get to these discussions this afternoon, well, maybe this morning, but we'll, for sure, see that. Great. Very clearly, okay? Okay, so line 13, we've called the bar function. Let's execute the bar function. How are we going to execute, starting with line four? Scope of bar? Hey scope of bar, I have an... LHS reference. It's really uncomfortable that I force you to use all these terminologies. I have an LHS reference for a variable called foo, ever hear of him? What's the answer going to be? Yes. Yup, I've heard of him. So he gives me a reference back to that. Is the reference that I get on line for a reference to the local variable foo or to the global one? Local. It's clearly the local because it was declared local. So it's kind of a first-come first-serve. I look for it in my local scope first, and I only go fish if I don't find it there. So if I find it there, it's always going to be used. In a sense, this is called shadowing because now that I have declared a variable inside of the function bar, everywhere inside of this function that I reference something called foo, it's always, at worst, going to be this guy and not that guy because every time we do a scope look up, we're going to find it first, first-come first-served, in this function bar. Everybody with that? So that's called shadowing. There's no lexical way for us inside beyond line four or anywhere inside of the function for that matter. But beyond line four, there's no way for us to say foo and mean the global foo, at least lexically. We could say something like window.foo, but that's a different mechanism altogether, okay? Okay, so we've executed line four. Let's execute, remember that lines six through nine are not there anymore because they've been compiled away, so let's execute volume 10. You have an RHS-- Hey scope of? Bar? Bar, I have an? RHS. RHS reference for a variable called? Baz. Baz. Ever heard of him? What's the answer going to be? No. Yes. I heard a no. You understand? We see it but it was declared here, right? Okay, so the answer is yes, I've heard of him because he was declared just recently. Okay, great. I need to go get his value, what is his value? His value is a function, right? So we go ahead and get that function value. And then how do we execute it? We call this open close parentheses and we execute that. So let's do the job of the execution engine. Let's execute baz. How is baz going to execute? Again, we're not passing in a value here, so we don't have to worry about the assignment part of the parameter. We're just going to execute baz, how does it execute? Starting with line seven. Hey scope of baz, I have a left-hand reference for a variable named foo. Do you know him? Exactly, good job. Hey, scope of baz, I have an LHS reference for a variable called foo. Ever heard of him? What's the answer going to be? Yes. Yes, because he was declared as a named parameter. So I get a reference back to that local variable and I can assign to it. When I assign bam here, am I assigning it to this foo or to that foo? Am I assigning it to this foo or that foo? Always to my local foo, right? Always to my baz copy of foo, right? Because of that shadow, okay? Now let's execute line eight. How's line eight going to work? Scope of baz, do you have a LHS of bam? Ever heard of him? Nope. What's the answer going to be? Nope, go fish. So where are we going to go next? Bar. Hey scope of bar, I have an? LHS. LHS reference for a variable called bam, ever heard of him? Nope. Go fish. Where are we going to go next? Global. Hey global scope, I have an LHS reference for a variable called bam, ever heard of him? What's the answer going to be? Oh, I just made him for you, I'm such a helpful guy. Many people wonder this very controversial part of this auto global thing that is kind of a nightmare. It's the bane of our existence but you wonder, now, I know that everybody in this room and everybody that's online and know that everybody writes perfect JavaScript now. Shockingly, back in the early days, people wrote bad JavaScript. I don't know how it's possible because we all write good code now. But they wrote bad JavaScript back in the day. And one of the things that was a problem is that they forgot to make their declarations and they left off their vars and things like that, so that's one possible explanation for how we arrive at such crappy behavior. The fact of the matter is, it's been removed as of strict mode because pretty much everybody agrees that's just terrible behavior. It just shouldn't be there, okay? Okay, yeah? In the result, is it I've created a declared bam in global scope and it's undefined? No, now it gets the assignment volume. Sorry, we finished executing line eight, which assigns yay to which variable? The global bam. Exactly. I have a question. Yeah. The baz, should it not take a parameter of foo? You're talking about line 10 right? You're saying should line 10 have a parameter? Well, it could, but it doesn't have to. JavaScript doesn't require you its variatic functions. So you can pass in values or not pass in values. You can pass in too few or too many or whatever. So just for simplification purposes, I chose not to worry about the assignment of parameter values. But yeah, you could pass in the number 42 here on line 10. You could pass that inside of those parentheses, and it would get passed along as the initial value for foo. So on line six and a half, foo would have that value the you passed in. Okay, we finished executing line 13. Now let's execute line 14. Now this is just a shorthand way. It's kind of like doing a console.log, but I'm asking to evaluate the value of that variable at the current time. So what is the value of foo on line 14? Bar. First of all, how do we execute line 14? Hey global scope? Hey global scope, I have an RHS. Why is it an RHS? Because it's not an LHS, okay? I have an RHS reference for a variable called foo, ever heard of him, global scope? And what does global scope say? Yup. Yes, I've heard of him. He was registered before. What is his current value when I ask for his current value? Is it bam? No. Is it baz? No. Clearly it's bar. Everybody follow that? Okay? Line 15. How's line 15 going to execute? Global scope, I have an RHS of bam, ever heard of him? Hey global scope, I have an RHS of bam, ever heard of him? What's the answer going to be? Yeah, I created him just recently. What is his current value? Yay. It's the yay value. Everybody with me so far? All right, now let's execute line 16. How does line 16 execute? Global scope. Hey global scope, I have an? RHS. RHS reference for a variable called? Baz. Baz, ever heard of him? Nope. Nope. Okay, here is where it gets different because in the other cases where we ask the global scope for an LHS and it went unfulfilled, it was an undeclared declaration. In non-strict mode, it automatically created one for us. Within RHS reference that goes unfulfilled, that's not automatically going to create a baz function out of thin air because how could it possibly do that? So what it's going to do instead is throw us what's called a reference error. So line 16 will result in a reference error because there is no identifier baz that's in any scope that's accessible to that current line of code. Baz was existing inside of this scope but he did not get registered in the global scope, therefore we cannot call him. Does everybody follow? That's true for both strict and non-strict? That's true for both strict and non-strict. So in non-strict mode, reference errors result from unfulfilled or undeclared RHS references, but automatic globals result from unfulfilled or undeclared LHS. In strict mode, they both result in a reference...
Function Declarations, Function Expressions, and Block Scope
Let's talk about the difference between function declarations and what we're going to call function expressions. Function expressions are a lot more common than you may realize from that name. We may not have a good name for them, but they happen all over our code. Let's look at line one and let's look at this function bar here. Is this a declaration? And the answer to that question is no, it's not. Here's your what-you-need-to-know definition. We could break it down grammatically, but I'm just going to give you the what-you-need-to-know definition. The way you know if something is a function declaration or if it's not a function declaration, it has to be a function expression. The way you know of the difference is whether or not the function keyword is the very first word in the statement. Okay? The very first thing in the statement. I do not mean the first thing on the line. I mean the first thing in the statement. So the statements can break over multi-lines. You can have multiple statements on a line. What we're looking for is that the function word is the first word in the statement. We go back to our previous slide, slide 15, line three, we see a function bar where the function keyword is the first thing on the line. So it declares that function in its current existing scope. So where did bar get bound in that example? When we did function bar, where was that bar identifier registered? Global. In the global scope. Here's the difference with function expressions. We look on slide 16, we see a function bar here. Is the function keyword the first word in the statement? First thing in the statement? No. No. So therefore, it must be an expression. Regardless of how it's going to be used, it's an expression. So in expressions, we often see expressions as anonymous functions. Many of you probably use them all over the place if you write jQuery code or any of those other ones. It's very idiomatic to just do function, open close parentheses. And we put those in our set timeouts and our click handlers and all over the place. It's called an anonymous function expression. I'll explain to you in just a moment why name function expressions are better, but this is a named function expression. Why? Because on line one, we see a name in the identifier position. We see function bar as opposed to just function open close parentheses. Everybody see that? Right there on line one. That bar name, however, because it's a function expression, that bar name does not get declared in the outer scope. Whereas in the previous slide, when it's a function declaration, the name was put into the enclosing scope. With function expressions that are named expressions, the name of the function expression is enclosed within its own scope. So the name bar here exists from lines one through nine inside of itself. We can reference bar here and that will work just fine. But when we try to reference bar on line 12 outside of the function, clearly, it does not exist. And we get a reference error. That's the difference between a function declaration and a function expression. Questions? Now why do we care about this named versus unnamed thing? So when you are in the habit of using, and many of us do this and I do it, I fall back to this all the time, when you use anonymous function expressions in your code, three major things occur that I consider to be three major negatives to using an anonymous function expression. What I would say is function expressions themselves, hugely useful. Use them all over your code. In fact, some people do them entirely. They don't do any declarations. Function expressions are great. What's bad is an anonymous function expression as compared to a named function expression, okay? And here's why. The free negatives to anonymous function expression. The first one is that when you have an anonymous function, if this bar did not exist, we have no way inside of the function to refer to ourselves, say, if you wanted to create recursion or if you wanted, if it was a click handler and you wanted to unbind the click handler or whatever. We have no way to refer to ourself from with inside of the function if we didn't give it a name. But by virtue of putting that bar name there on line one, we now have the ability to reference that function from with inside of itself if we needed to do recursion or whatever. There's a whole bunch of people that think incorrectly that the this keyword is a reference to yourself, and it's not. So you have no way of doing like a self reference unless you give it a name. And the nice thing about this name is that it's safe. When we put bar there, it's only going to exist within the function expression. It's not going to exist outside, so it didn't pollute the outer scope, just gave us a nice self reference, self-referential name lexically speaking. That's the first thing. The second thing, how many of you have ever had an error in production code? Maybe none of you. Maybe y'all write perfect code. I do lots of production code errors. In fact, most of the time, I sort of fumble my way to accidentally getting correctly working code. So I have lots of function errors, which means I do lots of debugging. And I do lots of debugging against minified code. Anybody ever seen a stack trace with anonymous function repeated like 15, 20 times? Happens all the time to me. The problem with anonymous functions is that they don't play well in debugging because it just says anonymous function. And especially when it's minified code, it's just anonymous function, line one, character 32,341. How helpful is that? Not very. But if you give it a name, that name gets used in the debug stack traces. So that's the second benefit of always using named function expressions as opposed to anonymous function expressions. The third and final reason, slightly weaker, is that it self documents code. When using anonymous function expression, you are required to look at the outer context to understand what that function is doing. But if you give it a nice descriptive name like handler, it's immediate looking at that function what it's doing. It's handling some event or whatever. So giving it a name makes the code a little bit more understandable. Yeah? We have a question in the chat for what are best practices when a function is assigned to an object. So I'm assuming a function meaning assigned as a property of an object? Right, yes. So I would say, in that case, you're definitely making it a function expression because it's not a declaration. It's getting assigned, so it's an expression, a value, a function, has a value. When you have function expressions, those function expressions should always have a name. So I would say you always want named function expressions. I can't think of a single example in any of JavaScript where an anonymous function expression is more preferable to a named function expression, except for the case where you're just too lazy and can't come up with a good name. Which happens. I mean, I'm guilty of that too. I write that. Yeah? Perhaps I missed this, but in the current case, wouldn't foo, ignoring line two for a second, would foo refer to the current function within this function if it were anonymous? So that's the problem with those... When you have a function assigned as an expression, you might be able to assume that variable was present. But what happens if later on down in the code on line 13, the global variable foo got rewritten to a different value? Now all of a sudden, you don't have that variable to reference yourself with, and you don't know that you don't have the variable. So you can't rely on something in your outer lexical scope. You can only rely on something that binds to your own scope. And by virtue of what you just said, the fact that we do some shadowing here also kills that idea. Okay, great questions. Any questions so far about function expressions versus declarations? Any more that I'm missing? Okay, moving on. I said before that the function was the only example of, I mean, the function was our only atomic unit of scope. That's actually a little bit of a fib. Very little known fact that, say, probably 99.9% of JavaScript developers are not aware that as of ES3, that is, way back to like IE5 and six days, as of ES3, when we got the try catch added to the language, it was specified way back then that the catch clause was block scoped, meaning that the variable that you declare inside of your catch clause exists only inside of the catch clause and not outside of the catch clause. So here we can reference the ERR inside of our catch, but when we try to reference that name outside, it's not available. A little bit of a caveat. IE6 screwed this up. IE6 did allow you to access the variable outside. But as of IE7 and above, and all other browsers, it obeys the spec and it blocks scopes into the catch clause, okay? So we have this name that's existing inside of this catch clause. We have an example of block scope. Is that anything more than just academic trivia? Put a mental bookmark there because we're going to come back to this a little bit later, okay? As another side note on this, by the way, I just thought of this as another side note, many of you probably use linters like JS lint and things like that, and I've seen many times where if you have the rule turned on that says you want to be warned about duplicate variable definitions and you have a bunch a try catches, if you do try catch ERR, try catch ERR and you repeat those all in the same scope, your linters will all complain at you saying that you're redeclaring that ERR over and over again, when in fact you're clearly not because it's block scoped. So it's not a multiple declaration. For some reason, unbeknownst to me, I cannot understand but for a decade or more, we've had linters that are not intelligent enough to understand the nuance of block scoped catch variables. And they all complain about it. So your only two solutions are, and I used to do this, ERR one, ERR two, which sucks; or simply turn off that linting rule, which is what I now do. Because it's annoying that it complains to you about stuff that's not actually a problem.
Lexical Scope
All right, so we've got two predominant models for scoping in JavaScript. There's a lexical scope model, which we've been discussing. That's the predominant scope model across most languages, but there's this other scope model that's called dynamic scope. It's not present in JavaScript, it's not present in hardly any language that you probably ever worked in. There's a couple of random examples of what dynamic scope is. So the bash scripting language uses dynamic scope. There's an opt in mode of Perl that allows Perl to operate in a dynamic scoping fashion, and there's some old academic languages that use dynamic scope. But for the vast majority of languages you've ever dealt with, you've dealt with scoping in the lexical scoping model. What does the name lexical mean? Well, that's kind of a fancy term that the lex, that refers to the parsing stage called lexing that occurs in the compiler when it's parsing through your code. The takeaway from that is that lexical scope means compile time scope. In other words, at the time that you wrote your code and that code then got compiled, the decisions for how all the scoping are going to occur were made in stone at that point. There were no more decisions about scope that were to be made beyond that lexical phase. So the compiler decides what your scope is, and we already saw that. We saw implicitly that when we walked through our code and we walked into a function, because there was a function there that created a new unit of scope and any declarations inside of it were attached to that new nested scope. And no matter how deep we go, that was all true. So we've already kind of seen this lexical scope thing happening. Now why would I point out dynamic scope? Well, I'm actually going to give you a contrast here in a moment of what dynamic scope actually would look like if we had it in JavaScript. It's going to look weird, but I'm going to give you a comparison because I want you to be able to compare dynamic scope to something that we're going to see a little bit later, which is the this keyword, okay? All right, I'm going to give you this metaphor, this diagram, it's a highly, highly technical diagram. It's a metaphor for you of what we've been talking about with scoping. And I want you to ignore the right-hand side of the diagram for now. That we will explain as we go throughout the rest of today, okay? We won't understand most of the right-hand side until the end of today, or mostly in the end. But on the left-hand side, we see lexical scope, and I want you to think of it like a building. It's kind of like the current scope is the first floor of the building. I'm looking for something on the first floor. I either find it there, or I don't. And if I don't find it there, what do I do? I go up one level of my scoping. I go out one level of my scoping. It's kind of metaphorically like taking the stairs in the elevator up to the second floor of my building and looking for it there; and going to the third floor and the fourth floor and the fifth floor. And eventually, I get to the top floor of the building, which represents the global scope. And I either find it there or I don't, but there's no more floors to go to, okay? So I want you to metaphorically think of this lexical scope traversal that we've been talking about as like going up the floors, up the elevator of a building, okay? Another way of visualizing it, a little bit more sort of attached to this code, is the idea of nested scope bubbles, okay? So there's a bubble around the scope of baz, and there's a bubble around the scope of foo, and there's a bubble around the outer enclosing scope, in this case, the global scope. And what I want you to notice about these bubbles is that they are strictly nested within each other. This is not like Venn diagrams, where we have bubbles overlapping with each other. You can't have the scope of foo partially in two other scopes, so whatever it's strictly nesting that's occurring here, okay? Now what's interesting about this nesting, is the nesting that occurs is fundamental to the way lexical scope works. The fact that baz is inside of foo as opposed to outside of foo is an irrevocable decision that you made at author time. You chose to put baz inside of foo, which means you chose to nest the scope bubble of baz inside of the scope bubble of foo. So these are author time decisions or what we call compile time decisions for how the scope works. What this means is that the compiler, when he's processing through this code and he processes the outer bubble and then the inner bubble and then finally the smallest bubble in the middle, when he processes through those nested scopes, he knows exactly what the scope looks like because it can't change. It's an author time decision, and your code isn't going to change itself at author time, I mean, at runtime, so it knows ahead of time. Even though we conceptually talked about that whole idea of like looking in my current scope and then going to the next one or whatever, doesn't actually have to do that because it knows at compile time where everything is, and it can cache all of those references. So from an optimization perspective, it knows categorically where bar is already. It doesn't need to look in baz because it knows exactly where bar is already. So as it's compiling, it can cache all of those references. It's an author time decision about your scope. So you made the choices about where you put your functions at the time that you authored your code.
Cheating Lexical Scope: eval
As with most things in JavaScript, however, there are exceptions. There are ways to cheat this. The first way to cheat on a lexical scoping model that JavaScript has is the eval keyword. Many people like to pronounce eval as evil, okay? So eval keyword, what is this all about? Well, the eval keyword takes any given string and it treats the string contents as if that had been code that existed at that point in the compilation. So when we compile this code, we would see that the function foo defined from lines three through six, we would see that, that function does not have a variable called bar in it. Everybody would agree with that, right? There's no variable called bar in it, so when I execute line five, I would expect what? I would expect for it to go out to the global scope and get this value bar here. But because we choose to pass in a variable declaration in the form of a string, an eval will run it on line four. It cheats it and it pretends that, that line of code had existed at compile time. So in a sense, what it does is it modifies the existing lexical scope of foo to add a new declaration to it at runtime. Does everybody see how that works? It cheated by modifying what would've otherwise been a write time author time lexical decision. It cheated and modified it at runtime. Guess what happens when you start cheating the optimizations in the JavaScript engine? Your code starts to go slower because any time that the JavaScript engine sees the eval keyword in any of your program, it has to assume that the scope of that function, as well as the global scope, it cannot optimize those lookups because it has to assume the worst case that at runtime, you're going to invalidate all of those assumptions. So it just simply doesn't do the optimizations at all, and when it doesn't do those optimizations at lexical write time, it makes your code run slower at runtime, just by virtue of having the eval present. Even if you're not actually modifying it, just by virtue of having it present, it has to disable some of its optimizations. Can it do still some optimizations? Yes, maybe. But by virtue of putting eval in your code, your code will tend to run slower. Of all the arguments against the eval keyword, to me, that's the one sort of unequivocal argument against the eval is that it would make your code run slower. Now there is a nice silver lining to this that as of strict mode, when you put a variable inside of an eval like this, it actually creates a whole new scope just for the eval statement. So yes, it's creating a new scope, but it's not modifying an existing one, which allows the engine to continue to do its optimization. So technically, the strict mode code, though it might break your assumption about how things work, the strict mode code is technically going to run faster. That's actually most of the reason why they put stuff into strict mode. It wasn't just about making better code, it was about making more optimizable code. Okay. But I would suggest to you never ever use the eval statement. Now there are some people that argue the eval is a still useful mechanism and that we shouldn't throw it out, and that it should still be available to people. So this is the way that I teach it, and everybody has their own different opinions on it. But the way that I teach it is if you have to ask whether or not it's okay to use the eval keyword, the answer is no. If you happen to be that one or couple of people in the world that's in that one or couple of niche circumstances where the eval keyword is necessary, you already know it, and you're not going to ask anybody, okay? So I will provide you, this is a public service announcement, I will provide to you this public service. From here on out, if you ever find yourself asking should I use the eval keyword or not, just give me a call, give me a tweet or something and I'll remind you, no, you shouldn't use it. It's just a service that I provide to all my students, okay? So if you have to ask, don't use it. What about the string set timeout syntax? It's the exact same thing, it uses the eval mechanism underneath the covers, does the exact same thing. Okay, so don't use eval. Now I would be remiss if I didn't give you some clues to what might possibly be one of those niche cases. Remember, I said to you I wrote a templating engine. What does a templating engine do? It takes other code and it produces new code from the other code. And it produces it as a string value. So now that I have a big old string of JavaScript code that is the compiled version of my template, how do I turn that into running code? Well, one way to do that is to have it saved into a file and load that file into a script tag or inject it or whatever. The other way to do it is to like eval it, or put a function constructor around it. I actually use the function constructor because it's better than eval, but the templating engine is one of those really small niche cases where you might need it. Maybe you need to do some kind of weird like, ES6 feature testing thing inside of an eval. There are really crazy corner niche cases, but the vast majority of you are never, ever, ever, ever, ever going to need to use eval. So if you find yourself feeling like you're in one of those cases, you're probably not. And you'll know it if you are. Does that make sense? Okay, now eval is one of the ways that we cheat. Turns out there's an even worse way that we can cheat lexical scope. There's a lot of different ways that people teach this mechanism, but anybody ever heard of the with keyword? Sorry, Kyle we had a question on set timeout. Does that mean we should avoid using that as well? You should avoid using set timeout with the string syntax. So you should never do set timeout, quote, and then calling a function, because that's code that will get evaled at runtime. I use set timeouts all the time where you give it a function reference. That's a totally safe way. But don't use the string syntax as the parameter to set timeout. Got it, thank you. Okay, the with keyword. Now there's a lot of different ways to explain it. Let me just kind of illustrate to you why with keyword can be useful, what was the reasoning behind inventing the with keyword. I've got an object called obj there on line one. He's got some properties like a, b and c, these values. And then I've got code like line seven and eight, where I want to do a bunch of operations with those properties. So you see that I'm kind of verbosely repeating the obj.reference over and over and over again, and that's really kind of annoying, all right? So what if there was a way to sort of shorthand that? And it turns out, the with keyword is how we can shorthand that. We can say with obj, and now, inside of that block, we assume that all of those variables are actually meaning to represent properties of our objects, so we can just say a equals b plus c and so forth, and so we kind of shorthand our way through it. People that do code golfing competitions in JS1k, they use the with keyword a lot, okay? So it can make shorter code, it certainly can make nice, easier code. There are some problems with the with keyword though. The first problem, kind of the major one that people point out, is that we see line 13. Look what's happening there, I'm basically saying d equals three. What's my intent? My intent clearly is I want to create a d property on the obj object, right? But that's now how it works. That's not what it does. Guess what actually happens when I run line 13. Hey object, you've got a reference-- It says hey object, you got a reference because it's actually treating this with statement as a lexical scope. And it's going to behave by the exact same rules of lexical scope that we already learned. So it's going to say, hey scope of with statement obj, do you have a variable called d? And what's his answer going to be? Go fish! So he's going to go to the outer scope, which in this case is the global, and he's going to say, hey global scope, I've got an LHS reference for a variable called d, ever heard of him? What's the answer going to be? Yeah, I just made one for you. Argh, so I created all the globals. Here I didn't want to create a global because it didn't already exist. When I say it on line... This is a typo, that should have been c equals b minus a. But when I say it on line 11, when I say a, well, I'm assigning the value in. So the property already exists and the lexical lookup works, and it works correctly. But when I make a reference to like variable, like line 13, that variable doesn't exist yet, and it creates it out on the outer scope. So that's reason enough to avoid the with statement, is that sort of that easy foot gun of creating auto global. But that's not even the worst thing, because I'd say that the with keyword is even more evil than eval. And the reason for that is because where in the eval keyword was modifying an existing lexical scope, the with keyword word at runtime is creating a whole new lexical scope at runtime. So it's doing even more to invalidate your assumptions at write time of what your scoping rules look like. And guess what happens when the compiler sees a with keyword in your code? It has to assume the worst, and it disables many of its optimizations. So in the same way that I'd say with eval you should avoid it, you should avoid the with keyword. And in fact, as of strict mode, the with keyword is completely disallowed altogether.
IIFE Pattern
Let's talk about some useful usages of functions and scopes. Remember, we talked about function expressions. That's where the function keyword is not in the declaration position. So here you see I did my bad practice of doing an anonymous function, but on line three, I have a function expression from line three to a, and then I've done this weird thing of wrapping it in parentheses, we'll explain that in a moment, but why am I doing that? Well, the reasoning behind it that's obvious from this code is I've got a piece of code, like lines five and six, that I want to wrap, I want to hide in a new scope. And we know that JavaScript, the unit of scope that we get is the function. So all we need to do is create a new function somewhere, and we'll get a new block of scope to wrap it in. In other languages, you could just put a new curly brace pair somewhere. But we don't have that quite the same in JavaScript. So the way we do that is to put a function somewhere. Well, now I could have done on line three, I could have said like function bob and made a named function declaration. And then on line eight, I could have executed that function by saying bob open close parentheses. That would have worked. But the problem with that is I would've leaked out a name. The name bob would've leaked out into the enclosing scope, which is not, it defeats the purpose of what I'm attempting to do. I'm attempting to hide some stuff, not to pollute my existing scope. So the way we can do this is what's called the IFFE pattern. We can make this function expression, the one that starts on line three and goes to here. We wrap it in parentheses to make it an expression. Remember, if that parenthesis was not there, would the function keyword be an expression or a declaration? Declaration. Be a declaration, that's not what we want. We want an expressions. So one of the syntactic ways we make an expression is to just not make it the first word, first thing in the statement by wrapping it in some parentheses. Now we need to execute that function right away, so we put another set of parentheses on the end of it, and that immediately executes our expression. Anybody in here have any experience with the Lisp programming language, or Lisp-like languages? This might look a little familiar. We're basically sticking a function on a stock and then executing. And that's kind of JavaScript betraying a little bit of its scheme list roots. We stick a function inside of this parentheses and we execute it. So it can be anonymous, or it could have been a named function expression. It would've been better if I had called it like function IFFE, given it a name so that I'm not, so I don't have the same problems that I have with anonymous functions. But in any case, when I say var foo, it's now going to attach it to that local function scope rather than polluting this outer scope. So inside of here, on line six, the foo is foo2. But on line 10, the foo is still just foo. Is everybody following that? Reminder, these little icons down in the bottom left are your clue that you should click on it and try it yourself, not just trust me. This pattern is extremely popular. I'd call this maybe in the top two most popular patterns in all of JavaScript. For a long time, we had it, but we didn't have a name for it. Back in like 2009, 2010, something like that, this really super smart dude named Ben Alman, he goes by cowboy on line, he's created more jQuery plug-ins himself than I think the rest of the jQuery community combined. I mean, this guy is extremely prolific, super smart, he's a trainer for Boku out in Boston. Really smart guy, but he said, you know what, we need a name for this pattern. So he wrote a blog post kind of suggesting that we give it a name, and the name that he suggested was immediately invoked function expression. Well, it's a function expression that gets immediately invoked. So it's an awfully good name for it, and we shortened that to IFFE, and that's now become sort of the de facto standard name for this pattern, the IFFE pattern, okay? It does not have to be standalone like this. These thing is going to exist as part of assignments, as part of passing, but the key hallmark of any IFFE is that you have a function expression, either named or anonymous, that immediately invokes itself. And that's the open close parentheses there in the end, okay? So the IFFE pattern is really popular. I recommended go reading his blog post about it, but that's what everybody calls it. It's extremely important because many of us have in our own code right now, we have a big file with a whole bunch of code strewn all about the code, and the problem with that is that this stuff is strewn all over the place, and we don't have any way to kind of protect stuff from being in the global namespace and collisions and all that. The most common solution to that is to put an IFFE statement at the top to start an IFFE, and put a closing IFFE, like line eight at the bottom of your file. And now automatically, everything in that file is hidden inside of the IFFE scope. So let's say you've got a hundred functions there and only one of those functions is actually necessary to be global. We go and wrap an IFFE around it, one second, Will, you wrap an IFFE around it and now all 100 of them are private. And then you take one of those and you add a property to the window object or whatever to make it global. But you hide 99 of them from being public that didn't need to be public. So as a little piece of homework, if you've got any of that spaghetti code where you've got a whole bunch of stuff in the global, go home and wrap an IFFE around it and make your code better. Will, was there a question? Yes, there was a question in chat. How would the IFFE pattern sound in our anthropomorphic compiler style conversation? That's a great question. So it's not a declared function. Well, obviously, it was a function expression that got compiled, but it's not a declared function. So basically, what the compiler would say, I mean, not the compiler, what the runtime would say is, I have a function expression. It's an immediate value, kind of like the immediate quote. Foo is an immediate value. It's an immediate value. So we reference that immediate value inside of our parentheses as opposed to having a reference identifier that we needed to do a scope lookup of. This is an immediate value, just like 42 or quote foo. We have the immediate value, and then we could immediately execute it with line eight. So it's more akin to those immediate values on the right-hand side than it is to some sort of lexical identifier. So that happens at runtime? What's that? That's at runtime. It was compiled ahead of time, obviously. I mean, it has to be compiled ahead of time. But from a runtime perspective, it's not going to get executed until it gets to line three. Okay? Great question. Would you recommend naming the IFFE? I do recommend naming the IFFE. Very non-idiomatic, but I recommend always naming your IFFEs. Just name an IFFE. But in your stack traces, you don't want to have anonymous functions anywhere. So give your IFFEs names as well. Okay, now what are some variations on the IFFE pattern that are really useful? The first is that an IFFE is just a function call, which means we can pass things into it. This is the call side of our function. We can pass values and variables into it, and we can name those parameters. And they don't have to be the same thing. So I said foo bar here just to be kind of generic, but the most common way that this is done, what I do in my code, is I pass in the window object, but I call it global. Now why do I do that? Inside my IFFE, I've got 100 functions that are private, and I got two or three functions that I need to make global. So inside of my function, I got 97 of them, just regular function declarations and variables, and those are all automatically private. It's obvious they're private. But anywhere where I say global dot in front of something, it's obvious to me that I'm creating a global. So as a stylistic choice, rather than the window, which is a little less obvious, I give an alias, if you will, to my window object. I call it global. And it's really obvious in my code which things are global and not. That's one way of using it, and that's what I like to do. Another extremely common example of this in the jQuery world is you're worried about making sure that the dollar sign really does legitimately point to the jQuery object because there can be other frameworks that sort of can collide with that, so what you do there on line eight, instead of passing in that foo, you pass in the named jQuery, the J capital Q, jQuery object. But you'd call it on line three, you'd call it dollar sign. That way, you know inside of your IFFE, you're guaranteed that the dollar sign points TO the jQuery that you wanted it to point to. And many people will do a mixture of both of those that make the window and the jQuery pass in multiple ones. But the IFFE pattern gives us a way to manually pass in an alias variables from the enclosing scope. Questions about IFFE? I've seen some... they pass undefined as the second argument. Is that for security or... I don't actually like this practice. There are some people that were concerned about the fact that in non-strict mode, the undefined keyword was a writable property. They were concerned that somebody may, on purpose or on accident, say undefined equals true, and then anywhere in your code where you were referencing the undefined, you'd get something you didn't expect. So the way they solved that, and the same way with the jQuery, they don't pass anything for the second parameter, but the named parameter on line three, they call it undefined. So they make sure that the undefined really is, in fact, undefined. I think that's overkill. I don't think it's a really good pattern to recommend, and it's fixed as of strict mode. So it's not an issue anymore. But there are people that do that.
IIFE Pattern Questions
Remember we talked about functions being our only unit of scope. It turns out that as of ES6, we're getting this exciting new thing called block scope. And it's coming to us via a new keyword called let. Let is going to be a cousin to the var keyword, okay? So just like we can do var a equals two, we can do let a equals two. And when we use the let keyword, it will implicitly hijack the scope of whichever block we happen to be in, and will add that variable to that block rather than to the enclosing function. Question? There's a question from Derek W. Is there any difference if you put the invoking parenthesis inside or outside the expression parenthesis. Good question, especially since a lot of people like to follow Doug, Doug Crockford. The question here is line three, I could've written, and this is one where I'm going to have to use the arrows so you might want to pan to this camera, but on line three, I could have had this parentheses, you see how I have the parentheses around the function and then I execute the function? I could have instead taken that parentheses right there on line eight and moved it to the outside so that there was an execution inside and just a non-functioning outer wrapper parentheses pair. And that actually, that second format is argued for by Doug Crockford. And this obviously is my preferred form. I'll just give you the two ways of thinking about it and you decide which one you like. They are functionally basically equivalent. I just saw a blog post the other day where there's a couple of weird cases that if you leave off semicolons, this pattern is more robust than Doug Crockford's pattern, but they're functionally basically the same. Here's the stylistic reason why you choose one or the other. Doug Crockford, pardon my French here, but Doug Crockford calls this hanging pair, and actually more appropriately, and let me go back to slide 23, he calls this hanging pair of parentheses that hangs outside, donkey balls. Kind of like those people that drive around with the trucks and those things hanging off the back. He doesn't like the look of it. He doesn't like the parentheses sitting on the outside, so he likes to put them on the inside, okay? And that's why he stylistically says you should do that. Really, actually, the truth is, the reason why he doesn't want to do that is because the fact that we have to wrap our function in a parentheses is kind of annoying. Grammatically speaking, it might be nice that we could just declare a function and at the end of a declaration, just put a parentheses pair. Just execute the declaration right away. That would be nice if we could grammatically do that, but that's not possible with the way the JavaScript grammar works. And so we have to put the wrapping pair of parentheses on there, just to get around that grammatical problem. And so he says if we have to put the parentheses pair on there to get around the grammatical problem, why not put them on the outside rather than leaving the donkey balls hanging out? I'll get to the question in just a moment. That the reasoning that Doug Crockford uses. (audience member muttering) Doug Crockford in brief. Doug Crockford's reasoning for this style choice is that we only have to put the parentheses there as a nod to the grammar. Theoretically, we would want just the open close parentheses in the end without the wrapping parentheses, but we can't grammatically. So if we have to put a wrapping parentheses there, let's make it on the outside rather than in this weird donkey ball style. Okay, so that's his reasoning. It's a valid stylistic choice. I don't agree with it, but it's valid stylistic choice. Here's my reasoning for why I like this better, because I actually like the fact, as I kind of referenced earlier, I kind of like the fact that this is sort of a nod to Lispy syntax. To me, this is clear that I'm putting a function, a function value on to my expression stack by wrapping it in a parentheses, and then I'm immediately executing the value of my expressions stack. And we do that in other places without functions, so I like the fact that this sort of, in a Lisp sense, it's treating a function as any old value that we can deal with. So that's my preference for why I like this style. These are just stylistic choices, they're not functional ones. I hope that clarifies the questions on the string. Don't we need to give the name to the function or something? We ought to name our functions correctly. I said we ought to name an IFFE or whatever but-- Okay, okay. Just to be short, the idiomatic way is everybody does an anonymous IFFE. I just think we ought to do named IFFE.
Block Scope in ES6
Back to our let keyword. The let keyword, as I was saying, the let keyword is kind of like var. It will declare a variable, but it will attach that variable implicitly to whatever block it appears in, rather than attaching it to the function. You recall from our discussion of the compiler, wherever it finds the var, it's going to attach it to whatever function scope it's in. Well, now, if it finds a let somewhere, it's going to attach that variable to whatever block it's in So essentially, implicitly hijacking our blocks. Here's one example. This is probably the most common reason why people use block skipping. Anybody do for var i? You put your little variable declaration of i right inside the for loop? Ever wondered why we do that? And I suggest to you, I think the reason why that became so common to us is that i value there is something that we only intend to use for the for loop. So there's something natural about saying if I only intend to use it for the for loop, let me put it directly on the for loop because stylistically I'm basically saying I'm not going to use it anywhere else, okay? Now in JavaScript, we have the ability to abuse and reuse variables all over the place, so we do it anyway, but we put the var there because we're trying to signal to ourselves and to future developers that i is only for the for loop, okay? But a var i here, if that had said var i on line three, then it would've attached to the function because we know how variable declarations, they attach to their function scopes. If we do let i, it will make that i actually attach to the for loop as opposed to the function. It will hijack the scope of the for loop. The same is true if we put a let inside of an if statement, like we see on line three. The let baz equals bar, that's going to attach the baz variable to the if statement from line two. And that's why on line nine, when we try to look at that variable, it doesn't exist because it's outside of its scope. So the let keyword will hijack implicitly the scope of whatever block it appears in. Okay? And that's basically any two pairs of curly braces, although not entirely. But basically, any two pairs of curly braces, the let keyword will just hijack that block. Now this is incredibly powerful because it allows us to put variable declarations following the principle of least disclosure, put them as close as possible to where they're going to be used as far down as is necessary so there isn't any possible chance that they're conflicting with other variables. It allows us variable reuse in different places of a function and so forth. A lot of power to the stylistic thing. We've been doing this before. Probably, some of you have code where you put your vars inside of your ifs because stylistically, we wanted to do it. We now have a way to enforce functionally what we were already doing stylistically. So there's value there, there's value in terms of early errors, if we're accidentally referencing variables that we shouldn't. There's some potential performance benefits because now these values can be garbage collected earlier since they're inside of blocks that go way. So there's lots of possible functional benefits to go along with the stylistic choice of blocks skipping. Does that mean that we're going to do all block scoping? I don't think so. There are some notable people on the TC39 committee that have literally said let is the new var, and they've encouraged people to do a global find and replace and replace all occurrences of var with let. In fact, anecdotally, a few years ago, I worked at Mozilla. Mozilla has had the let keyword for like a decade. So I worked at Mozilla and we wrote JavaScript code for the Firefox browser. And the first two code commits that I tried to get into the code base were rejected because I used vars instead of lets, and they have that culture that said because we have the let, you should always use let. I don't agree with that, and maybe that's one of the reasons I don't work there anymore. But nonetheless, some people think let is the new var. You should replace them all. I think you're going to use both. I think you're going to continue to use var declarations for things that you want to make available to a whole function, and lets for things like for loops, where you want to put it in one specific location.
Problems with the Let Keyword
There are some problems with the way this particular formulation of the let keyword exists, some problems, at least, in my opinion. The first problem is that the let keyword, we're going to talk about hoisting in just a moment, but the let keyword does not hoist, which means that right here, I'm showing the let keyword at the top of this if statement. What if this if statement was a thousand lines long, and I stuck the let keyword right in the middle of those thousand lines? You would be of the habit of thinking that, that baz variable would exist for the entire if statement. It turns out it would not exist until halfway through the if statement. So that's a gotcha that you're going to have to worry about. You're going to have to remember essentially to manually put all your lets at the top of your blocks. That's kind of a problem. The other problem is it creates an extra mental taX for re-factoring. Again, I know most of us in this room, and most of you online, you already write perfect code and you don't have to re-factor. But for me, I usually will write a piece of code and it doesn't work, so I wrap an if statement around that, a for loop around that and a try catch loop around that, and eventually, after putting enough blocks and moving things around, I accidentally stumble upon correctly working code. That's my process, I don't know about you. But for me, when I'm using variable declarations, I don't have to worry about putting blocks everywhere. Now that I'm going to use block scoping, I'm going to have to think a lot more about my blocks. Okay? I can't just arbitrarily wrap a new block somewhere or put something somewhere because I might accidentally create some block scoping that I wasn't thinking about. So there's some extra mental tax to worry about when block scoping is introduced, okay? So that's part of the problem. And the third thing I would say kind of leads from that second one. When you're talking about implicit block scoping, which is what the let keyword here is, it's implicitly sort of hijacking the scope of whatever blocking exists; when you're talking about implicit, that's usually harder to maintain than explicit mechanism. So I prefer to have explicit scope blocks rather than implicit ones, because if I'm going to deal with the mental tax, it would be nice if there was a way for me to know this is clearly a block of scope rather than this is both an if statement and potentially a partial block of scope or something like that. So for me, I prefer this other form, which in the previous slide we would say would be a let declaration. These are called let blocks or let statements. It's kind of a similar syntax, except we create an explicit block, like we see here on lines two, three, four. Create an explicit block for that binding to exist in. And that variable exists only within that block and not outside of it. Now rather than overloading my if block with additional scoping, I have an explicit block that I can reason about that block as an independent unit, just like I reason about functions. So I prefer this form to the previous form because I think it forces my, first of all, syntactically, it forces my declarations to the top of the block, which means they will always exist for the whole block. I don't have to worry about that. And it creates these explicit blocks, so it's a reduction of the mental tax by a little bit. That's just my own personal opinion. Unfortunately, there's a major problem here, and that is that the TC39 committee decided to reject that syntax from ES6. It may come later, but as of ES6, they decided to take the form, which I think is the lesser inferior form, and they kept that and they rejected this, and I actually cried for a few days because I really felt bad about this. I'm out in the habit of trying to tell people I think this is going to make code better, and they rejected it. So the first question I ask myself as a way to solve this, is there some kind of like solution in terms of, you know, a syntactic form that might appear? And I came up with this idea. I said, what if I create an explicit block with just two curly braces? That's not very idiomatic in JavaScript. Most people don't even know that you can do that, but you can. You just put any two curly braces somewhere and put my let declarations, force them to be in one statement, all at the very top of my block, and even put a little comment there. And it looks a lot like a let block. It doesn't behave exactly like one, but it looks a lot like a let block, and so maybe that would solve my problem. And that was my initial solution to this, of them not putting in the let syntax. But then I got to thinking, you know, whenever we have problems where languages are getting in our way and they're making things harder for us, the solution to that is not write worse code. The solution is make a better tool. So I thought, what if it would be possible to make a tool that would take code that looked like that and make that code run inside of standard JavaScript browsers even though it's not standard JavaScript? Is that possible? Many of you are aware of tools like CoffeeScript, to transpile something that's not standard JavaScript into something that is. And therefore, now it'll run. So could we create a transpiler that would do this? And I did that, I made a tool and it's called let-er. And it's not just a theoretical thing. It's a real tool, I use it in my own code. It's got test and everything. But what it does is it looks through your entire code base, and you'd use it in your build process just like you use any other build tool. It transpiles any let blocks into something else that will work in JavaScript, in standard JavaScript, but it leaves everything else alone. So it's not like CoffeeScript where it's rewriting all of your code. It's only going and looking very targeted at your let blocks. This allows you to start writing let blocks right now and use them even though they're not standard. So it's a nonstandard transpiler for you. But there's another benefit, because guess how I actually accomplished the block scoping? It will take code like that, and it will transpile it, oops, to this code. Now this code looks awful and ugly. What I'm actually doing is forcing a try catch condition by throwing something and forcing a catch block. Remember how I told you the mental bookmark that catch blocks are block scoped? So we can wrap a try catch block around something and force this variable foo to be block scoped. It will actually be enforced by the engine. And not only that, but now that works today in all browsers instead of waiting only for ES6 browsers. So you have a choice. You can wait around for ES6, or you could start using block scoping today by virtue of a tool like let-er. Now nobody would write code like that. It's terribly ugly. But you also wouldn't write the code that comes out of the CoffeeScript compiler. That's also equally ugly. The point is that this is compiled or generated code as opposed to authored code. You write code that lets you maintain your code nicer with let blocks, and then you compile it to stuff that runs. Final note that I'll make on this. A lot of you may think, oh, it's ugly and it's certainly non-performant and it's terrible and some crazy hack that Kyle came up with. The official TC39 tool, it's called tracer, it's maintained by the team at Google. It's called tracer, it is an ES6 to ES5 transpiler. And the committee uses this tool to test all of the things that they're specifying for ES6 to be able to test them in existing JavaScript engines, and it transpiles things to work in ES5. Guess what the tracer compiler does when it comes across a let keyword. Produces a try catch. So this is actually the official, blessed, standardized way that you can use let block scoping with a let keyword today, is to use something like tracer or to use something like this let-er. The vantage of the let-er tool is that let-er lets you use the more, I think, the more robust form of the let block form. But either way, that's a path forward for using block scoping today. By the way, that's a general pattern for what the TC39 committee has suggested. Some people are of the opinion that we should, we're just going to have to wait around for a decade until all browsers are ES6-compatible. And that sucks. That's not the way to do it. So their suggestion is that you start using ES6 today. Even though they're still working on it, there's a lot that's already finished. And they suggest that you use ES6 today and you start using a transpiler in your build process. So you'd put tracer in or let-er or any other combination.
Dynamic Scope
Remember when I discussed dynamic scope earlier? I was talking about this comparison to lexical scope. And lexical scope was an author time thing. I want to give you a depiction, a quick sort of theoretical depiction of what dynamic scope would be, just so you have this contrast in your mind. Again, this is theoretical, this doesn't exist in JavaScript. But if we had dynamic scoping inside of the function foo here no line two; on line three, when we reference a variable, bar, we can clearly say lexically that bar does not exist. But if dynamic scoping were the model that JavaScript uses, it would not look for where the code was written, but it instead would look at the call stack. It would say, does function foo have a bar? If not, where was function foo called from? So it'd walk one step up the call stack and it would say well, I was called from baz, so it would look at the scope of baz to see if there was a variable. And that should look bizarre to you. It should feel awkward and unnatural, like something really strange is going on. That's because it's a totally different model for scoping than what we've all learned. We've all learned lexical. Now if you had never learned lexical scoping and you had only ever written dynamically scoped languages, this wouldn't feel so weird and unnatural. It's not that one is right and the other one is wrong. There's a reason why lexical scoping is like 99.9% of all languages, because it's probably superior in some ways. But there are perfectly valid models that are just different. And the key distinction, the key comparison that I want you to take away from this is, the decision for how scoping works in dynamic scoping, is a runtime decision as opposed to, in lexical scoping, it's an author time decision. So keep that distinction, the author time versus runtime distinction. And that'll be important when we talk about the this keyword after lunch.
Quiz: Scope
Let's review where we've been so far. What types of scoping rules does JavaScript have, rule or rules does JavaScript have? What's the scope rule called? Lexical. Lexical scoping (mumbles). What are the exceptions? How do we cheat lexical scoping? Eval and the with keyword. Those are our two ways to cheat with the exception is lexical. What are the different ways that you can create a new scope? Function. Functions create a new scope. What else? Try catch. Catch blocks create a new scope. What else? Curly braces. The curly braces with the let keyword in ES6 will create a new scope. Okay? What's the difference between undeclared and undefined? Remember I mentioned that earlier? Can anybody remember? What's the difference between undeclared and undefined? Undefined has a value. Undefined is a value. Is a value. What is an undeclared? It hasn't been registered in-- It's never been declared yet. So another way of explaining undefined, some people say undefined means it's a variable that doesn't yet have a value. That's not really correct because a variable can have a value and then not have a value. So really, the proper way of thinking about it if you want to sort of conceptually is, undefined means doesn't currently have a value, or currently, the value is, it's an empty placeholders or something like that. It's another way of thinking about it. But it means, explicitly, if you have an undefined value, then there definitely was a declared variable. Because if there's not a declared variable, what you're going to get back is a reference error. That makes sense? So keep declared and defined, even though they sound like synonyms, keep them separate.
Hoisting
There is this conceptual model for how JavaScript works, and that conceptual model is called hoisting. As I will suggest to you, it's not really physically what actually happens. If you open up the spec, you'll not find the word hoisting anywhere, because hoisting isn't actually a thing. It's a mental construct that we have invented to explain the behaviors of JavaScript. So I'm just going to present to you what hoisting, the concept of hoisting is. When we look at this code, if I asked you, what is the value of the variable on line one, or what happens, how does line one execute, going back to what we already discussed earlier, back before our break, how is it going to execute line one? It won't do it first, it'll run through and define a and b. Ahh, exactly, good catch. The fact is that it will go through first and compile this code before it executes it. We all think in terms of no, it's just going to execute lines one through six in order. But that's not true. What it's actually going to do, it's going to go through and find the declarations first. So rather than thinking that a would be undeclared on line one, in reality, the best way to think about this code is that those variable declarations were moved to the top. They were treated first during the compile phase. And then the assignments were left in place. And this moving to the top thing is what we call hoisting. The fact that declarations have variables and the declarations have functions, it is said that they are hoisted to the top of the code. They're not actually hoisted. It's just that they get handled during the compile phase. So you could think of it as the compile phase is lines one and two, and the execution phase is lines three through eight. Does that make sense? All the LHS stuff is happening at compile time? That's correct. And RHS is (mumbles). That's exactly correct, yeah. Kyle? Yeah? I'm not sure if this was intentional or not, but the code (mumbles) link on a previous slide for 37 links to the same thing as the one on slide 32. 37. The code here links to where? I'm sorry. The previous example of the try catch let hack. Does it? Yeah. That's definitely a mistake. Thanks for catching that. Okay. So this is how the JavaScript engine conceptually would handle it or would treat the variables. This also goes for functions, by the way. Let's think about how this code is going to work. Anybody have a guess how it's going to execute line one? Well, first, it's going to say I've got an a, I've got an LHS reference called a. Is it going to find an a declared? Obviously yes. Then it's going to say I have an RHS reference for a b. Is it going to find a b declared? Yes. Yes, because the function name is declared during the compile face. So it's going to try to execute the function, b. It's going to say I've got an RHS reference for a variable called c. Is it going to find c that's declared yet? It was declared because the compiler declared everything first. But what value is c going to have at that point? On line one, what value does c have? Undefined. Still undefined. So when we return back undefined, undefine is going to go into a. Everybody follow that reasoning? Let's try line two. Got an LHS reference for a variable called c. Does it exist? Yes. Okay, I've got an RHS reference for a variable called d. Does it exist? Yes. What is its value at this point? Undefined. So we're going to attempt to execute a function that is undefined, which is obviously going to be in here. Does everybody see why the function expression did not get, as we say, hoisted? Whereas the function declaration did? This is the proper way to think about this code. Functions are getting moved to the top first, then all your variables get moved. And then you start executing as of line seven. So it's very clear from this look of the code why d doesn't yet have the function expression in it. Questions about hoisting? I shy away from saying think about code in terms of hoisting. I'm explaining it to you because it is the predominant conceptual model that JavaScript developers are taught. I think it's much better to just think about things in terms of what I've already taught you about compilers. The compiler pulls out the declarations first. So course, it's going to find all declarations. But this is another visual way of thinking about it. So you can't call a function expression before... Before it's been given its value. In the code Yeah. Okay. Now it is also true in this previous slide here, I'm sorry, slide 40, I indicated that the function b got hoisted first. And you may wonder how do you know? Is that true and is it possible to even tell? It is technically possible to actually prove that functions are hoisted before variables. And this next slide will illustrate sort of a proof of that. This next slide will run. The foo call happens even though the declarations have not occurred in the code because both of these declarations will get moved. But if you were to think about this in terms of the hoisting, first, this function is going to get hoisted. And then this function is going to get hoisted, which overrides it. So multiple duplicate function declarations get overridden. But then bar foo equals two, that var foo, when it gets hoisted, it's an ignored declaration because there's already a variable called foo, and it holds this function here. So the way this code executes, this foo will end up running this function. It won't try to be value two or foo. Takeaway from this is don't redeclare stuff a whole bunch of times and don't make a bunch of, you know, don't share the same name redeclared a bunch of different times and you won't have this weirdness. Why does the function get overridden but not the variable? Why? It's just the way it's specified. Function declarations are a declaration that implies the value comes along with it. Variable declarations, the value is left as executable code so it doesn't get hoisted. Now some of you may be asking why is it that JavaScript does this hoisting thing? Why does hoisting or why does the compiler have to pull out the declarations ahead of time? Why is that required, because it seems like it might make you code harder to understand. Wouldn't it be easier if JavaScript just worked in a top-down fashion? So how many of you know what recursion is? Okay, recursion, for those of you who didn't raise your hand, it's fine; recursion is when a function calls itself, okay? Foo calls foo over and over again until some terminating condition. Was there a question, Will? Yeah, there was a request for you to shout the line number when you're pointing at stuff because it's hard for people to see. Okay, try to do that. I will try to do that more. Okay. So recursion is when a function calls itself. Anybody ever heard of mutual recursion? Not as many people. (mumbles) in computer science-y, geeky thing. I'm one of those people that geeks out on that stuff. Mutual recursion refers to two or more functions calling each other. And there's a whole class, a small class, but there's a class of computer science problems which are not practically solvable. They are technically solvable but not practically solvable without the concept of mutual recursion, because it requires tracking separate stacks, okay? So a calls b, b calls a. A calls b, b calls a until some terminating condition when they stop calling each other, okay? So mutual recursion, if you think about it, would be impossible in a language without hoisting because one of the functions would always be declared too late. A would be declared before b, but b requires a, so it would have to swap places, and then they couldn't happen. As an example here, for instance, a, b and c are calling each other in a mutually recursive way. One of these would always be declared too late unless there was some concept of the declarations getting hoisted. And interpreted language, if you will, could not handle this because it would try to parse function a and it would say, well, I don't know about function b yet. So you would have had to put b first, and then it could have done b and then a, but b would have required c to be first. So c would have had to be first, but c requires a to be first. So it would be impossible for it to parse this if it didn't have some concept of mutual declarations. Anybody ever wrote C code way back in the day? The C language? Remember header files? Header files are manual hoisting. You're putting the declarations at the top of what the compiler handles because that compiler doesn't automatically hoist. So JavaScript just automatically hoists rather than forcing you to do header files, okay? As a slight piece of trivia, I'll give you about 15 seconds if anybody wants to try their hand at figuring out what this mutual recursion value returns. Something greater than 20. It is something greater than 20. I will grant you that. You only get two guesses. And no, 42 is not the right answer. I love it when I ask this question because like 3/4 of the room is content, and then there's 1/4 of the room that's like, oh, F that, I'm not even trying. (laughter) Is it seven? It's not seven. Who's going to keep going? 14, 15, 17. 34, 35? Not 35. Close enough for me. (laughter) 36? Not 36. Five seconds. The answer is 39. Let me show you how we get there real quick. We start out passing in the value one into the function a. Is one greater than 20? No. So then we pass one plus two, which is value the three, and we pass that into b. B gets the value three, it passes that straight through, but it puts a plus one on the stack. So we'll come back to that one. Remember, we've gone through b once. There's a plus one hanging out. So it passes through the value three, and three times two on line 11, three times two is the value six. Six gets passed back into a. Is six greater than 20? Nope, so it keeps going. Six plus two is eight. Eight passes into b. Eight passes straight through. We have another plus one on the stacks, so we got plus two on the stack. Eight passes through. Eight times two is? 16. 16 passes into a. Is 16 greater than 20? No. 16 plus two is 18. 18 passes into b. 18 passes straight through, we got another plus one on the stacks, so we got a plus three. 18 passes through, 18 times two is? 36. 36. Is that greater than 20? So we return 36. We go back through the stack three times. 36 plus three is 39. All right. This is just illustrating, I already kind of told you about this let gotcha. I forgot I had this slide. This illustrates for you technically the spec. It's a terrible name for it. They call it the temporal dead zone between the beginning of the block on line two and where the let occurs on, in this case, on line four. If you try to reference the variable before it has been declared with a let, it's called referencing it in the temporal dead zone, and it's a reference error. So no hoisting with lets? Yes, I say there's no hoisting with lets. When I said that out loud on twitter, Allen Wirfs-Brock on the TC39 committee was like, no, no, no, it's not hoisting at all, you shouldn't call it that. But they like to call it the temporal dead zone. I would just tell you, lets-- don't hoist, because that's the what-you-need-to-know definition.
Exercise 1
So I'll orient you to the exercise. What you want to do, and again, as a reminder both for you here in person, as well as for you listening in online, if you only have one copy of that exercises folder, before you start modifying things, I recommend just making a separate copy of your exercises folder. That way, at some later date, you can go back to a pristine copy of these exercises and try your hand at them. But we're going to open up... I got to go to day one. We're going to go to the exercises folder, go to EX1. You can open up the readme file and the JS file. All right, the readme is going to explain what you need to do. But also, you're going to come over here to your browser and open up EX1.html, which is going to load your EX1.js. And you're immediately going to get an error on the very first line of your program. That's on purpose, okay? So what this says is it wants you to fix the code so that our that our program will correctly print out the full alphabet, a through z. That's what the program is designed to do. Right now, an error is out. We got to fix those errors. This is asking you to take what you've learned about scoping, about hoisting, about IFFEs and all that other stuff. Put all that stuff together into a way to solve the problem. Now I have constrained your ability to solve this problem. You're not allowed to just put console.log a, console.log b in a program to solve it. So I've constrained your solution. You cannot have any global variables at all. If you look at the file, you'll see everything's global. So first thing you're going to have to solve is that you have to stop having any global variables at all. The second thing is that you cannot delete or combine any of the existing function declarations. You have to leave the function declarations or whatever as they are, you can't delete or combine them. You cannot create any new functions, except there's an exception that you can create IFFEs. And that's a big hint because you're going to need to create some IFFEs. And you cannot rearrange the order of any of the declarations. You have to use what you know about the way hoisting works to solve your problems. The things that you can explicitly do is you can declare extra variables as long as they're not global. You can modify a function declaration and turn it from a declaration into an expression, or from an expression into a declaration. And you'll probably need to do that. You can add or remove various statements or expressions like the returns or IFFEs or parameters. And the explicit answer here is you want to search for making the fewest changes possible. This does not call for you to change every line of this entire program to solve the problem. So go through it one at a time. Try to constrain yourself to these rules and see if you can get it to print out a through z. I will walk you through an answer to this in a few minutes right before we take our lunch break.
Exercise 1: Solution
Going back over what we talked about, the first thing that our readme tells us is we can't have any global variables at all. What was our most likely solution for preventing global variables? IFFE. Anybody remember that? So if we were to simply put an IFFE to start our program, go to the very end of our program and finish our IFFE, and then for good measure, I might indent all of this stuff but not technically required; now, everything is private, okay? So if I were to save this code and run it... Actually, let me do one quick thing. Before I start making changes to this code, I'm saving them. All right, so if I were to save this file and run it, now I didn't actually fix my bug, but now you'll notice obviously we're on different line numbers because now I've solved the problem of global variables. So my next problem is well, I know line three is causing a problem because it's trying to do a, and a is a variable. It's a function expression. So I said one of the things that you're legally allowed to do is change an expression into a declaration. So if I change that to just simply function a, now that we don't need the semicolon anymore, and I save my file, now a worked. But b is broken. All right, let's look for b. What's the problem with b? B is down here, also listed as a function expression rather than a function declaration. So let's change b into a function. Now you may be tempted to start fixing a whole bunch of these. But again, try, in the spirit of the exercise, try to fix as little as possible. Okay, now we got oops being printed, not an error. How is that happening? Well, it's happening because we got our function here that's printing out oops. But we are not allowed to change that, and we have a variable c. Let's see, if we've got a different, oh, we've got one down here. What happens if I change that into a declaration? Does anybody know how that might work? Because of hoisting, it's going to override the previous declaration. So now when I save my code, now I get uh-oh, undefined, not a function. So now I'm getting a problem with the function d. Why am I getting a problem with the function d? I'll just verify here real quick. I'm trying to call d... So I'm trying to call d way up here at the top before d can actually run, because d hasn't been given the value yet. Does everybody see that? Everybody see why that's true? Because the d gets, the capital D gets his information for the function, he gets that from this line. But we're trying to execute ourselves up here at the top on this line. So I could start trying to solve all kinds of other problems but I could also observe that maybe there's a trick that I should pull about not executing my function at the beginning, like I'm doing. Okay, what if there was a way to take out this function call entirely and execute it in a different way? So what if I were, for instance, this is just one of possible ways to do it, I could return that a function from my IFFE, and I can execute my a function at the end of everything, rather than at the beginning of everything? So if I save that code, again, not the only way to solve that problem, but now I've made some progress. Now I've gotten the e, e is trying to do something that they can't do, so let's go and look at the function e. E is trying to call f, but f is still... Isn't this capital F yet. I mean, the lowercase f hasn't been given the value f yet. I need to double check myself real quick. I'm forgetting in my fixed version one of several ways that I can solve that. Ah, I remember now, okay. So another way of solving this is to deal with the fact that the problem is that f isn't getting the value early enough. But f is a parameter name, which means I could pass in the function itself. So if I came here to e, (mumbles) e was... Who calls e, sorry. The d function. If I came here, if I passed in the f function, now he's going to get assigned before he tries to be called. All right, now g is having trouble, so let's go and see what. G is having trouble because it's trying to call h, but h is a function expression, so we can change h to simply be a function declaration. So we take advantage of hoisting. Okay, well, now I made it all the way to k, but it just stopped, it didn't do anything else. So what happens with these k values? Well, oh, I've got to do statement that says I need to call the next function. So what is my call to my next function going to look like? Well, if you were looking into this, you would see that I was creating these functions from my string by saying rest of i. So... Rest of i plus one, oops. So if we put in that call, now everything finishes to the end, and I've got a through z. However, there's still a problem. Anybody know what the problem with this code is? (audience muttering) Can't do global variables, exactly. So one way of solving this without very much change to my code, is to create an object for those variables, for those functions to be assigned into. Double check, what did I do? (audience member muttering) Ah, you're right, absolutely, good catch. So now I need to call object.k. There we go. All right, that was the spirit of the exercise. I know it's kind of a silly one, but it was to get you to think about your hoistings, get you to think about how you can play with scope. You notice, a bunch of these we left as expressions because one of our solutions called for simply executing the a at a later time.
this Keyword
We will continue on in our discussion of scope enclosures. We're going to take that interesting detour where we're going to talk about the this keyword, which might start, as we start to look at this, it might look a little bit strange. Why are we talking about that right in the middle of scope and closure discussions? But again, as I mentioned before, the idea here is I want to give you a good solid contrast between the lexical scoping model, which is an author time decision, and this mechanism that JavaScript has called the this keyword, which, as we're going to see, starts to approximate or look a little bit more like the dynamic scoping model. So to explain the this keyword, or sort of what-you-need-to-know definition, we're going to say is that every function, while it's executing, has a reference to its own current execution context. And we'll call that reference the this keyword. Now technically, the execution, we're fibbing a little bit because technically, the execution context includes more than just the this keyword. There's more to it. There's your local variable stack and other things like that. But for our purposes, all we care about is that this bindings, so our execution context will say is are this keyword. What do we mean by that execution context? What we mean by the execution context is where the function is called, or how the function is called when it's called. So we're going to need to go back and look at that call site. And to draw your attention back to this diagram before, we saw the lexical scoping model was like taking the elevator or the stairs of this building on the left-hand side. What we're going to see now is this mechanism that we're going to look at is kind of like, metaphorically, telling us the address of which building on the right to go into. So you got a bunch of buildings downtown in your city, and each one of them has a different address, and you need to meet with somebody. The first thing that they're going to have to tell you is the address of the building to go to. Before you can even go into the first floor of the building and start looking for their office, you're going to have to know their address. So this mechanism that we're going to talk about, that is the this keyword, is going to essentially tell us the address of which building to be looking at. The rest of today, we will expose what the rest of that building metaphor is. But right now, we're talking about how do we figure out which first-floor to go into? All right, so there are four rules for how the this keyword gets bound, and they all depend upon what we call the call site. The call site is the placing code where a function gets executed with its open close parentheses, okay? So contrary to everything that you may think about, where the this keyword means something to do like myself or self or anything like that, you're going to have to set all of those conceptions aside. You may have conceptions that the this keyword has something to do with classes and object-orienting and instances and all that other stuff. You're going to have to set all of that completely aside. And you're going to have to set aside in general what the this keyword means in any other language. So I'm not making a value statement on JavaScript's mechanism is good or bad or better than anyone else's, but I'm going to tell you the four rules, and this is, again, sort of defensible from the spec. I'm going to tell you what the four rules are for how the this keyword will get bound in our code for normal functions, and you just have to learn those rules. And I'll tell you not only the rules, but the order of precedence. In other words, which rule takes precedence, which rule should I ask about first? And what you will need to do then, if you ever have another problem with figuring out the this keyword, is to go find the call site and ask these four rules in order of that call site, and they will definitively tell you what the this keyword will be. That's all you need to know. You don't need to know anything at all about except for where that function is called, when it's called, how does it get called? That's the only thing that matters. Doesn't matter where a function is declared. Doesn't matter whether there's func, classes or objects or anything else involved. The only thing matters, that matters, is what does the call site look like? And we'll take a look at those four rules. So the first of those four rules that we're going to look at is actually the fourth rule in terms of order of precedence, and it's the rule that I call the default binding rule. So let's examine this code. We've got a function foo up here, lines one through three, and on lines one through three, this function declares that it makes a reference to this keyword. It says this dot bar. So immediately, we know that the this keyword needs to reference an object. It's not referencing like a primitive, like a number or a Boolean. It's always an object. It's referencing an object that we can look at properties on. So we're expecting that there should be a non-empty binding or reference to some object, and we should be able to ask whether or not that object has a bar property on it. And if it does, we should be able to get that bar property's value. So when we call foo in the normal sense, I'm going to call this the plane, undecorated sense of the word for a function call. That looks like line nine. The call site on line nine, the function stands alone all by itself. There's nothing special to it. We can pass parameters if we need to, but it's just a reference to the function, and there's nothing else to that function call. And when that is what the call site looks like, the default binding rule applies. And I would say that this is also true even with IFFEs. So it's when there's just an immediate function right there and it just gets called with a parentheses. So in our IFFE case where we have a function expression there, same sort of deal. It's the function expression or in this case, a reference to the variable called foo. But we get that function object right there and then we immediately call it with an open close parentheses. That's a normal function call, and in that case, the default binding rule applies. The reason is that none of the other three rules that we're about to learn will apply, so it falls through to the fourth catchall rule, the default rule. Now the default rule says this. If you are in strict mode, default the this keyword to the undefined value. If you are not in strict mode, default the this keyword to the global object. That's what the default binding rule says. So it gets a default value, and it'll either be undefined or it will be the global. And it can't be anything but one of those two values. And it's dependent entirely upon the strict mode. And by the way, it's not the strict mode of the entire program, but it's the strict mode of the code running inside of the foo function. So if the foo function itself did use strict, then that would be the case. It doesn't matter what the outer code is, it matters only the contents of the function. That's what's going to define our strict mode here. Okay, so our foo function is being called like that, same thing as if it was an IFFE. It's going to hit that default rule. Now you remember when I showed you earlier in the spec, I showed you kind of the genesis or the support for that is right there in the spec. If you refer back, if you go back to the videos afterwards, you can go back and see, I showed you where it had those two points and one of them said use the this rule; otherwise, use the global. So you can see right there where the default rule is coming from, okay? So that's first of our four rules, is the default rule. Let's learn the second of our four rules. We're kind of learning them in reverse order of precedence by the way, and that's on purpose. The third of our four rules, or the second rule that we're going to learn, which turns out to be the third of our four rules in precedence, is what I'm going to call the implicit binding rule. So let's take a look at that. What you'll see, I've got a couple of objects. I've got an o2 and an o3 object here on lines six and seven. They both have bar properties on them that have unique values to identify them, but you also see that they have references to our same foo function. Now it's important to note that in JavaScript, everything is a reference to an object. Everything is a reference to a function. You never have, where it's like the foo variable on line one sort of owns the function, and then this guy is like a copy of it; or anything like that. They're just references. So we have, in this case, on line six, we have two different references to the foo function. We have the global variable foo that's referencing it, and we have o2 dot foo is referencing it. They are both peer references to the same function object. Neither one of them owns it more than the other regardless of where it was declared. They're just references. So we just sort of implicitly put a reference to a function on an object. And then on line 10, you can see we can say o2 dot foo. So we can make a reference to a function via the object property reference. And when we do that, when the call site looks like o2 dot foo, in other words, when there is an object property reference at the call site, the third of those rules in terms of precedence kicks in, which is the implicit binding rule that says that, that object at the call site, what's called the base object here, or the context object or the owning or containing object, depending on how you think about it, but there's a lot of different ways to explain it, but that object becomes the this keyword, the this binding. So in our case, when we call o2 dot foo, it's the exact same function being called. But when that call site, when the call site is o2 dot foo as it is on line 10, then the this keyword will point to o2, and that's why we get bar2. And the exact same thing with o3. Is everybody following so far? Two of our four rules already shown just on this one slide. The implicit binding rule has an owning or containing context object at the call site. The default rule has nothing but just a plain old normal function call. Just to further reinforce the fact that it doesn't matter where a function is declared, nobody owns it more than anybody else, in this case, I'm doing the exact same thing as in the previous slide, but I put my function initially on o1, and then I made another reference to it on o2. Absolutely no difference in terms of its behavior. The only thing that matters is what the call site looks like. When I say o1 dot foo on line 12, I get bar1. When I say o2 dot foo on line 13, I get bar2. And when I say foo without any kind of thing at the call site, I get my default binding rule, which gives me bar3. By the way, if it wasn't obvious, the global object in this case is, in the browser, it's the window. And note, it's an actual object called the global object, but the global object has properties on it, which correspond to, that are the same as any global variables. So if I have a global variable called bar, there's also a global object property called bar. They're not copies of each other, they are one and the same. There's a global property and a global variable, and they're one and the same. Yeah? Question from online chat. Is there a place where they can see these rules in writing? Yes, in my book, You Don't Know JavaScript, youdontknowjs.com. The second title, this and object prototypes, chapter two. I described it all in exquisite detail. You can go to the spec and look through all the different ways like I was talking about earlier, and you can divine for yourself these rules. But I've tried to distill these rules down into the human-friendly form, the what-you-need-to-know form and that's what I'm presenting here. Okay. So our default rule and our implicit binding rule. Now I want to take a little bit of a detour for just a moment, and I want to talk about our binding confusion problem that happens with people, because despite, yeah, sorry, was there another question? Yeah, another one came right after, sorry. What happens if o2 doesn't have a var property, does it default back to the global bar? Great question. We're not going to fully be able to answer that actually accurately, but I would say it definitely does not refer back to the global bar. Does not? It does not. But we'll have to understand the prototype chain before we can actually fully answer that accurately. And we'll get to that by the end of the day. So remind them, if you would, that if I don't answer that fully for them by the end of the day, to re-ask.
Binding Confusion
So I want to take just a little detour here and talk about some binding confusions. And I'm not just making this up. This is actually, I mean, this is fake code, but this is distilled from an actual question on Stack Overflow that I ran across, and it's not the only one where people try to create this connection between these two models that we've presented between the lexical scoping mechanism and the this scoping mechanism. And the way that it usually occurs is somebody has some other function somewhere, like baz, the baz function here on lines five through seven. Maybe that one's declared as part of a third-party utility that they don't control. So they don't have any control over it, but they know that, that function makes a reference to something like this.bar. And then they have a function that they do control, like the function foo, and they've got a local variable inside of their function called bar, and they want to be able to invoke that function in some way, that when he makes a this.reference, it will reference their own local copy of the variable, okay? And that may or may not be something you ever attempted to do, but people attempt to do this, where they try to take some function and make it reference their own local lexical environment, make the this reference somehow cross over to their own lexical environment. What I will state plainly is that it is impossible to create a crossover between the lexical environment and the this binding mechanism. They're just two fundamentally different mechanisms, and they don't crossover. But there's an attempt that people make to do this, and it's a well-meaning and well-spirited attempt. Here, I'm trying to say I want to call this function in such a way and make it so that, that bar variable references my bar variable. And so what you can see here is they're trying to get the this reference to somehow magically reference their local lexical context. We don't have any reference to our own local lexical context. It's a thing that exists, but we get no reference to it in our code. So we don't have a way to tell them, make the this point to my own lexical context, and yet people attempt to do this. So this question was posed on Stack Overflow. I'm attempting to do this, and again, it was a different form of the code, but I've distilled it down to the problem. This is what I'm attempting to do, and it doesn't work. And I was dismayed to flip, you know, to scroll down a little bit and to see the first answer was the one with the big green checkmark on it, and it literally had several thousands upvotes. And I looked at the code that was posted, and I'll show you again the distillation of the code that was posted, it is abjectly wrong. And yet thousands of people have upvoted it as the correct answer. And people are giving it the green checkmark and saying, well, this is obviously the right code. It's a testament to the fact that people are not rationally thinking about the this mechanism the way it actually works. They're thinking about the way they want it to work. So I just want to caution you against that. I want to call it out. I want to show you how incorrectly they tried to solve this problem. This is the distillation of the way they tried to solve this problem. They said, okay, well, what I really need to do is I need to make that baz function, I need to make a local reference to it. So I'll say this.baz is equal to baz, and then I'll invoke that function as my own local context. And that will somehow magically kind of import that function back into my local lexical environment, and then therefore, it'll be able to reference the bar. Again, this is the answer that got lots and lots of upvotes. It's like nobody actually tried the code because the code is still abjectly broken. It doesn't actually work. But everybody thought this was the correct answer. And I'll explain to you, based on the same rules that we've already learned, why this is abjectly wrong, why this doesn't work, okay? In the previous code, we were attempting to somehow make the this reference here on line seven reference our own lexical context. So the way they tried to solve that was say, well, if I make a this reference here, and I sort of import the function, that should work. But as I already explained to you, the this reference gets set by the call side of the function call. So to ask on line three what does my this reference look like, I need to ask where does foo get called and how does it get called? So we come down to line 11 and we say which rule would apply when line 11 executes the function? This is global. It's going to be the global because we're in non-strict mode, and the default binding rule will apply. Does everybody follow that? So on line three, we're essentially saying global.baz is equal to baz, but there's already a global.baz. This is a complete no op. It's nonsense. It's a testament to somebody not actually understanding the mechanism that they're writing about. So this is a complete no op, this line here. On line four, we're saying global.baz. Now when the baz function is called, what is the call site for baz look like? Which rule will apply? Default. Not the default rule, the implicit binding rule, because of, look at our call site, we have an object.reference here. So there's a containing object, but it happens to be the global object still. So it's still, just like the previous slide, it's still going to be global.bar here. It's not going to be the local bar that you wanted it to be. And no matter how hard you try, I put this challenge, I mean, I tell people not to do this, and people always take it as a challenge. Oh, I can figure out a way. I assure you, no matter how hard you try, there is no way to create a crossover between the this mechanism the way it gets bound, and your local lexical environment. Put metaphorically, if we go back to... Sorry, let me go back a few slides. Put metaphorically, what you're attempting to do, I assume that you probably have this here, but not (mumbles). Do you have those little cross bridges between tall buildings where you're on the 10th floor and you can walk across instead of going all the way down? So what you're attempting to do metaphorically is to create a cross bridge between your two buildings. And what I'll just tell you is it's impossible. You can't create a cross bridge between them. They're two separate mechanisms like they're two separate buildings, and you can take one elevator, or you can take the other elevator. But you can't take both of them at the same time. It's just not possible, okay? So your brains may attempt to do that, and if you ask a question at some point, and I refer you back and I say you're trying to create a cross bridge, it's not possible, that's why. I just have to remind you that regardless of what we attempt to do, there's no way to make those two, you know, mix. They are two separate mechanisms.
Explicit Binding
All right, let's learn the third of our rules. This is the second in our order of precedence. The third of our rules will call the explicit binding rule. Now the explicit binding rule says if you use .call or .apply at the call site, both of those utilities have, they take as their first parameter a this binding. It's called a this arg. So when I say foo without anything, it's a plain, normal, default binding rule. We know that. When I say foo.call and I pass in obj, then it says use obj as my this. So we're explicitly stating which this binding we want to occur. And the same is true with apply. .call and apply do have different behavior with respect to arguments, but with respect to what we're talking about the this binding, they're one and the same. They have the same behavior, okay? So our explicit binding rule says at the call site, if there's a call or apply that's explicitly specifying a this, use that object for the this. Is everybody following that so far? So foo.call obj is going to make sure to do it, same thing with foo.apply. If we said obj, it uses the obj as its this keyword. Let's take another little detour. I need to explain one of the most frustrating parts of all of the this binding mechanism, is this idea that many people complain about, you may have experienced this yourself in your own code. Many people complain about the idea that your this bindings kind of get lost, or they accidentally fall through to the global object. It has this annoying property that these functions are very flexible, that the this binding can mean a lot of different things. But sometimes, we write code in such a way where we want for the this keyword to be very predictable. For example, you create yourself a little controller class, a little object with a control that represents different methods for your controller actions. And each one of those methods says this dot to reference various states on your controller object. Any one of those methods that you're talking about, you have a very specific object in mind when you reference the this keyword, and it's your controller object. So anywhere that method gets executed, you expect for that method to be executed with a this keyword pointing at the controller object. Everybody with me so far? It's pretty common in JavaScript programming. So everywhere that you call a method, you always say, like, controller.method name and everything works fine until such a time as you make an Ajax call and you say, as your call back, I want to call one of my controller method. So you pass in a reference to the controller method, you say controller.method name is your call back name, and when it gets called, the this binding is wrong. It's fallen back to the global. And you pull your hair out, and you're frustrated. Or until such a time as you attach that to an event handler like a click handler on a button. Whenever I click the button, I want for this controller method to be executed, and you get frustrated because now that this binding, somebody made it be the button itself, rather than my controller object. In all cases, the this keyword ends up being what we don't want it to be. We wanted it to predictably be our controller object. So it's this frustration that we get into where the this keyword, it simultaneously gives us all this flexibility, but at the same time, it's too flexible in many cases, and it frustrates us, okay? So one solution to that problem is wouldn't it be nice for us to construct a mechanism in such a way that our methods can be passed around the way that we're accustomed to passing them around, but the this keyword inside would always be predictable? And that mechanism is what we call hard binding. Is there a way to take a function and hard bind the this keyword so that it's a predictable object? So let's take a look at a way that we might derive a hard binding. I will essentially derive the mechanism that's now built into the language, okay? So let's take a look at hard binding. How would we do that? Well, okay, so I've got a foo function here, lines one through three. It makes the same sort of reference that we're seeing before, but look at line eight. Line eight is different. I make another reference to the same function. This one I call a ridge. So it's a reference to the original function. And then I overwrite the foo. I don't have to overwrite it, but here I overwrite the foo with a whole new function. This case, a function expression. Now what is that new function that I'm creating coded to do? If you look on line nine, whenever that foo function will be called from now on, he will always call the original function because we still have a reference to it, but he will force the this reference to always be obj. No matter how foo gets called, a ridge will always be called with obj as the this binding. So down here, when we say foo, it's going to be bar, the way we would expect it to be, even if we tried to override it. We say foo.call on line 12, and we say I want you to use obj too. It still would print out bar, and here's why. Because inside of this function, right here in this little gap on line nine, right here in this gap, there is a this binding that'll point to obj too. But you notice, the rest of the function completely ignores whatever the this binding of the wrapper is. It forces it to be obj. That's what we call hard binding. So now we have a reference to foo that if we passed it in as a callback to an Ajax call, or if we attached it as a click handler or any number of other ways that we do asynchronicity, we pass function references around, no matter where we pass it, no matter how it gets called, it's always going to have a this reference that predictably references obj because it's hard bound to obj. Does that make sense? So you can see why that's a useful mechanism in some cases. Now it's reduced our flexibility of our function call, which is kind of a trade off, but the benefit is now we don't have to worry about people calling it incorrectly. It's always going to predictably reference the object I expect it to reference. This is still a little bit clunky though, because we've got this global variable, essentially this ridge that's kind of hanging out that's kind of clunky. Could we make ourselves a utility to do this? The answer is yes, we could make a little bind utility that would do the same thing for us. So the first step that we might do to create a bind utility, we make ourselves a function called bind. He accepts two parameters, he accepts an fn parameter, the function; and he accepts an o parameter being the object that you want to bind for this. Now what does our utility do? Our utility creates a whole new function that is hardcoded to call fn with o as its this, as you see on line three. Same thing as the previous code, but now we've created it as a reusable utility, and it doesn't have one of those variables hanging out in the global space to potentially have an overwrite and reference or something, okay? We use it in the exact way that you'd expect. Down here on line 13, you say foo is equal to bind foo to obj. Now when we call foo all by himself on line 15, it still references obj as bar. It's not falling back to the global because this is not the call site anymore. That's an important nuance. This looks like the call site, but where is the call site? Call site is actually right here. Everybody see that? A little subtle nuance, but super important detail. So when you're finding the call site, if there's a hardbound wrapper around it, that's not the call site anymore. You got to go inside the wrapper to find the call site, okay? When we call it with what would otherwise look like the default binding, in fact, it uses the explicit binding and uses bar, and even if we tried to override it, it would still use the obj. Question so far? The online folks are wondering which Stack Overflow question you were referring to. Do you have a link to it we can get later? I don't have a link to it. This is two years ago when I found it and made this first slide so I don't remember it. I just remembered tearing my hair out when I saw it. But I don't remember the link to it. Okay, so the hard binding is nice, but it's still a little bit clunky that we've had to create a global utility called bind. Is there a way we could kind of stick that utility somewhere and make it a little bit less global, a little bit more useful, maybe potentially useful to all functions? And it turns out that we can put that utility directly on the function prototype. So temporarily, for the purposes of this slide only, I'm going to call my utility bind2, and I'll explain in a moment why I call it bind2 instead of just bind. So we'll come back to that. But temporarily, what I'm going to do is check and make sure there isn't already a bind2. And if there isn't already one, I'm going to create one. And what that guy does is he does this peculiar thing, which I'll explain in a minute, but this thing should look familiar. He returns back a new function that's a wrapper function. Now what does that guy do? He's not using the dot call anymore on line six. He's using a dot apply so that we can pass along any arguments; and he also has a return there on line six, so return any return values back. So now, in the previous slide, our little bind utility was kind of limited because he didn't have any return values or arguments and that kind of sucks, but this one is kind of the pass-through pattern. He'll pass through any arguments and pass back any return values. So just transparently forces the this to be o, like we asked for. Now what about the trick on line four? We're saying var fn is equal to this. Why would that be the case? Well, let's go and look at the call site. Down here, what we're talking about is that bind2 is a utility, it's a function, so all functions are going to have a this binding, right? Let's look at where bind2 is being called. When bind2, the function, is called, what does his call site look like? Which one of our rules applies right here? It's the implicit binding rule because we have a context object here. And so inside of our utility function, what is this keyword going to point to? Foo. Foo, which is the function we wanted to point to. So it's a little syntactic trick. We don't have to pass in the function manually, we can just get it by reference to the this function. So we have our function, we have our o, and we can force them to be married together, if you will. And it works exactly like you'd expect, foo is equal to foo.bind2 obj when we call foo. We can even pass in parameters, but we know it's definitely going to reference the obj, exactly like it has in previous slides. Any questions so far? All right, the last thing I want to explain about this hard binding rule is it turns out, this is such a useful mechanism that the JavaScript, as of ES5, added .bind directly to function prototype, so it's already built into the language as of ES5. So we don't need our little bind2 utility. Its built in. And in fact, not only is it built in, we can go to the MDN page, the Mozilla Developer Network page, and I can scroll down, they actually provide a polyfill for the function. What this polyfill was designed to do is it's designed to allow you to use function.prototype.bind in pre ES5 browsers. That's what polyfills are for. So it has a little if statement to check to make sure that you're not overriding the one that's already there. So make sure you're in an older browser. And it defines one. And you can ignore some of the details here. What you take away from this code is that it's a lot more complex than what I showed you in that slide of bind2. So the reason I called mine bind2 is six months from now, I don't want you to go back to the slide deck and think that the one that I provided is a good polyfill, because mine is very limited. If you're going to use a polyfill for the bind utility, and I recommend that you do, come to MDN and use the one they provide. Not only is theirs better, it's more adherent to the spec, it's also more powerful. It has other capabilities that the one I provided you in the slides doesn't have. So this is the spec-compliant version of the bind utility, represented in pre-ES5 terminology. And some of it's a little confusing. A few of the tricks are beyond the scope of what we'll discuss here, but you should notice that it's basically doing the same thing. It's got a function here that it forcibly calls apply with a this reference to it. So mechanically, it's doing basically the same thing as what we were already derived.
The New keyword
All right, so we have learned three of our four rules. Let's go to the fourth of our four rules. Again, I'm going to have to ask you to set aside any preconceptions that you have about what the new keyword means, because many of you, especially those of you coming from other programming languages, are accustomed to the new keyword having something to do with instantiating classes. And what I will tell you is that a, JavaScript does not have classes, regardless of what you've been told; and b, the new keyword has absolutely nothing to do with instantiating classes, regardless of what you've been told. So you have to set all those preconceptions aside. I promise, we'll come back to the class topic. That's our next big thing that we spent a lot of time on today. We'll come back to that, but right now, I just have to set that aside, and let me explain to you what the new keyword actually does, okay? When we put the new keyword in front of any function call, it magically turns that function call into what you might call a constructor call. Still has nothing to do with classes. But it turns a function call into what the spec might refer to as a constructor call. And so, what we see here is that the new keyword put in front of any function, the function isn't a constructor function, it's that a function call becomes a constructor call when a new keyword is stuck in front of it. So essentially, you can put the new keyword in front of any function that you ever have in your whole language, and it will act as a constructor call. Okay, so it's a modification to the way the function is being called. When we put the new keyword in front of that function call, it's going to do four things. And if you're in the process of writing down notes, because I don't have these explicitly in a slide, this is something you'd want to write some notes on. There are four things that occur when the new keyword is put in front of a function call. The first thing that occurs, a brand-new object, a brand-new empty object will be created out of thin air, just poof! Creates it out of thin air. It's the first thing. The second thing, you're going to want to put an asterisk next to this item because I'm going to say what it is, but it's not going to make sense. And I'm going to have to come back later and explain to you what the second item is. The second thing that occurs to our brand-new poof out of thin air object, is that object gets linked to a different object. And again, what is that linkage? What is that all about? You're just going to have to hold off, and I'm going to have to explain it later because we're going to come back to it, okay? But that's the second thing that occurs, is our poof brand-new object gets linked somewhere. The third thing that occurs, this is important to our discussion, that brand-new poof object gets bound as the this keyword for the purposes of that function call. And the fourth thing that occurs when a new keyword is put in front of a function call, is that if that function does not otherwise return anything, then it will implicitly insert between lines three and four, like at line three and a half, it will implicitly insert a return this. So that brand-new poof object will be implicitly returned for us from the purposes of the call. What this should mean to you is you could take any function, I don't care what the function does, it doesn't even have to reference a this keyword, take any old function in your program and put the new keyword in front of it, and you have hijacked that function call as a constructor call. It will also do all the stuff that it's supposed to do, but in addition to doing all the stuff that it's normally supposed to do, it will also do those four things that I just said just by virtue of you putting the new keyword in front of it. Okay? So it's kind of this side channel, create an object, link them, implicitly bind them and then send them back to me, okay? So we see that here when I do new foo, I'm going to create a new object out of thin air. The linkage will ignore. It's going to pass it in as the this, so when I say this, I've got a brand-new object, I can add a property to it. So I can say on line two, object.baz, and I can add a string to it. In fact, when I do this console statement, I'm asking for this.bar, there is no this.bar, because it was a brand-new empty object. So we're going to get undefined printed here. And at the moment, the baz variable exists, but he has no values so we're going to print undefined again. So this console statement prints undefined, undefined on purpose. But the final thing that occurs is that there's implicitly a return this. So that newly created object gets assigned back to our baz variable. If you were to try this code by clicking the code me icon in the bottom left, and I encourage you to do so, you could make your own line eight that could then say baz.baz, and you'll see the string value as it was assigned on line two, because you've got the object back and he has a property on it. That's the fourth and final way that a this keyword gets bound. It can be bound to a brand-new object that it was created as part of a constructor call hijacking. Questions about the new binding? Now I've been mentioning to you all along as we've been going, there were four rules. Now we have the four rules. And I mentioned to you that there was actually an order of precedence, because depending on how you construct things, you could have a call site that might match two or three of these different rules at the same time. So which one takes precedence? Which one is the most important rule? Let me present to you in order the four questions to ask about your this keyword. These are the four things that you should write down on a Post-it note and stick that on your monitor next to the Post-it note that has your password, and you will never be concerned again about how the this binding works. Because this is very simple, you find the call site, you ask these questions in order, okay? The first question, oh, I'm sorry. I forgot, this code proves the order of precedence. I'm not going to belabor it. You can go back if you want. You can try the code yourself. You can type this kind of stuff in if you want. It will prove the precedence to you, but I won't belabor it because I'm just going to tell you what the precedence is. First rule, was the function called with the new keyword? If so, use that object. That means that the new keyword is able to overwrite any of the other rules because it's the most precendent of the rules. That could be a surprising result, which I'll explain here in just a moment. Second rule, if there wasn't a new keyword, the second rule, was it called with call or apply? Was there an explicit binding? If so, use that object. Third rule, was it an implicit binding rule? Was there an owning or containing context object at the call site? If so, use that object. And fourth and final, we default to the global object except in strict mode, which we default to the undefined value. These four rules in order. Now let me show you a surprising result, at least it was surprising to me. Remember how we talked about hard bound functions? Hard bound functions were basically a variation of the explicit binding rule. Remember, we wrapped a function around it and we put some special stuff into it to make sure that it would be forcibly calling a particular this? Where does that fall in the order of precedence? Any guesses where the hard binding rule falls? Two. At number two, which means that the new keyword is even able to override hard binding. Subtle but weird point, which I can prove by going back here. I won't explain how the code works, but there's a trick here and you can see the evidence of the trick right here. Inside of the polyfill for it, it's checking to figure out whether or not the this keyword came as a result of a new call or not. And if so, it uses it. Otherwise, it uses what you pre-bound. It took me about three hours to figure out how that code works, so I don't have time to go over it now, but you'll just have to take my word for it. All right, so those are our four rules in order of precedence. Learn those rules, remember those rules. That's all you ever need to know, and you have no more excuses for ever being confused about the this keyword again. Find the call site, ask those four rules.
Quiz: this
So quiz time. Without cheating and looking back at that slide, I want you to tell me those four rules in order. What are they? New? New. Explicit binding with a call or apply or the bind. Implicit. Implicit binding with an owning or containing object. Default. Default rule. Was there a question from the chatroom? No. Okay. All right, those are our four rules in order. How do you borrow a function through implicit assignment of the this? How did the implicit binding work? When you call the function, it was in the context of an object, so it had implicit-- Right, we mutated an object to put a reference to that function on the object so that we could then say object.method name. Exactly. So sometimes, it's okay to put a method reference on an object and kind of implicitly borrow it. Other times, that's kind of awkward but that is a way to implicitly bind. How do you explicitly bind the this keyword? Call and--. Call and apply. Bind, you know, implies that it does a .apply. How can you see a specific this to a function? Using the bind function. The dot bind utility. Now why was that beneficial? What was the usefulness of doing that hard binding? (audience member muttering) If you wanted to be predictable, you want your methods to always go against a particular object. You're annoyed that it's always getting lost. Creating a hard bound reference to that solves that problem for you. So that's a good thing. What's the downside of doing that? Give us flexibility. Yeah, the trade off... If you've gone to all the trouble, I want you to ask this as a thought question, if you go to all the trouble to put hundreds of annoying this.references all over your code base and then you find yourself doing everything with hard binding, why did you do a this binding? Why didn't you just use lexical? Because you're going down this harder path and then cutting off all the flexibility, which is the whole benefit and the reason why you use that mechanism. They're two separate mechanisms, they have two separate capabilities and trade-offs and things like that. Hard binding is one of those sort of cheating things where you're fixing one problem; but you're trading off that you're losing that flexibility. So I'm not saying that hard binding is wrong. I use it from time to time. But if you find yourself doing most of your code with hard binding, you might want to ask yourself, maybe I shouldn't use the this keyword at all, because maybe I'm doing it the harder way. Lastly, how do you create a new this object? By using the new keyword. Not a trick question, by using the new keyword. Exactly. By using the new keyword. All right, so that's our this mechanism. And again, to reinforce, you can see that the this mechanism is dynamic. It's a binding mechanism that looks for things at runtime. It's entirely based upon how you called something. You can have the exact same function called in four different ways and get four entirely different bindings. Does that make sense? So that's the contrast between that look up mechanism and the lexical scope mechanism, which was hardcoded at author time. It's not dependent upon how something is called or where, it's only dependent upon where it's declared, where you put those nested scope bubble.
Closure
Closures
This last discussion that we're going to have here, and then we're going to have another exercise. This last discussion in this module is called closure. And closure is one of those magical concepts that you may feel very confident about, or you may feel like, man, I've never been able to understand closure. Anecdotally, when I was learning C programming way back in the day, it's one of the earliest languages I learned. And I was actually not even in college yet, so I'm in high school, little dumb kid and I'm trying to learn this stuff, and we didn't have Google, and the way we learn now, so it was like, trying to find used programming books at the bookstore to try to learn stuff. And when I was trying to learn C programming, without the benefit of the internet and this was like, early to mid 90s, without the benefit of much of the internet. What I would run across in books is would run across the discussion in the C language, of pointers. And it was always, every time I ran across a discussion of it or if I found somebody talking about it or heard somebody talking or whatever, I would always get this sense that pointers were like this magical level of enlightenment that you had to get to. You could write the C language without understanding pointers and you could do a certain amount, but you could not really fully experience all that the C language had to offer, until you understood pointers. And for a long time I didn't get it, and always felt like, oh, one of these days that lightbulb's going to go on, and I'm going to get pointers. And then it did. And truly and honestly, it was that lightbulb moment where I was like, oh, I get it, and I can reference pointers from pointers, and do all kinds of address math, and the whole language opened up to me at that point. So anecdotally, it's sort of like, we feel that way about closure. When you're first learning the language, you may hear people talk about closure and you may think that it has something to do with functions and being passed around, and scope, but you're not really quite sure. And you know that people say that when you get closure, the whole language kind of opens up and your eyes are opened to this whole other side of the language. And I do recall a time when I didn't understand closure fully and then I got it and I had a different perspective. All that is to say, that if you are hoping for today to feel like that magical enlightenment moment, I have to warn you that it's going to be a slight letdown. Because it's going to feel a little anti-climactic when I explain to you what closures actually are. And that's on purpose, not because I want to dash your hopes or anything, but because everything that I just spent the last three hours teaching you, is the fundamental basis for how closures work, and now when I explain what they are you're going to be like, ugh, of course, I've already been using closures, I didn't even realize it, I didn't have a name for it. So it's going to feel a little bit like an anti-climactic letdown, it's not, this magical moment. It's going to be a little bit more like when Neo first sees the Matrix. It's not a new thing, the Matrix was always there, he just didn't have a way to see it, and now you're going to see closure in a way you couldn't see it before. Ok? So I'm going to give you the what you need to know definition for what closure is, and I'm going to explain it. Now, it turns out that closure's actually a mathematical concept. It comes from lambda calculus, and I don't know what the F lambda calculus even is. So I can't give you a mathematical definition, I just know that it is, 'cause I can read a Wikipedia page. Comes from lambda calculus. I do know, sort of as a side note, I worked with this guy one time years back, and this dude was hard core, like Mr. Computer Science. I mean he was brilliant, and he knew about the Y Combinators and all this stuff, and he had a tattoo on his arm of the lambda form of the Y combinator written out with the lambda symbols and stuff. He had a tattoo of the lambda, I don't even know what it meant. It was literally Greek to me, I had no idea what that was. So I can't give you that, I can't give you even an academic definition, per se. But what I am going to give you is the what you need to know, the practical way to say this. And this is my definition, so when I ask you what closure is, I'm expecting you to give me this definition back. Hopefully it's helpful. If beyond this class you want to discard it, that's fine. But here's the definition. Closure is when a function remembers its lexical scope, even when that function is executing outside its lexical scope. Let me say it again. Closure is the capability for a function to remember and access its lexical scope, even when that function is executing well outside of its defined lexical scope. We understand that a function has access to its lexical scope, we've already seen that before. When I had bar inside of foo, bar could reference a variable in bar, but it could also reference a variable in foo through lexical scope lookup, we already understand how that mechanism works. The capability for bar to continue to reference that same scope lookup, even when bar is executing outside of it, is what makes closure. So let me illustrate. Here I have a function, outer function foo. He's got a variable called bar on line two. On line four I declare an inner function. Remember my inner nested scope bubbles. So I've got a scope bubble around baz, and that's inside of the scope bubble around foo. We know that baz can reference bar. We know that baz can say bar, and it will first check for a local variable on line 4 1/2, it doesn't find it there, so it goes up and it finds it in the enclosing scope on line two. Everybody remember that, right? So we understand that, and that mechanism is most appropriately described as lexical scope. But because JavaScript has first-class functions, functions can be passed around and they can be executing in entirely different environments. So if we take a reference to the function baz, and we pass it outside of the function foo, in other words down here on line eight, I take a reference to baz, and I pass it outside, I pass it as a reference to another function. On line 12, when I execute that baz function, he is still able to access the lexical scope in which he was defined, even though he's executing outside of that lexical scope. Does everybody see on line 12 why he's executing outside of the bubble? There's a bubble around lines one through nine, he's executing on line 12. But it still works, he's still able to access that variable, and that is closure. The fact that that lexical scope stayed attached to that function, no matter where he got transported. And it's not just a copy of the lexical scope, it's a reference to the existing lexical scope, it's kept alive. And that's closure. And you're going to say, awww, I've been doing' that for years, and I didn't know that's what that meant. Yeah, that's your letdown moment, right? Let's see a couple of examples of other--other more common examples.
Closure Examples
You can also return functions from functions, so passing them as parameters is one way, returning them. Here I take the inner function, in this case an inner anonymous function on lines four through six, I return it out, so on line 10, the first set of parentheses gets the inner function back. And in the micro-second between the first set of parentheses and the second set of parentheses, that function object has been transported outside of his lexical scope. In that he's still able to access the lexical scope, and that is closure. Questions so far? This should start to look a little more familiar with some of these examples. When you pass a function into a set timeout. Any kind of callback. And that function is able to remember the variable. The way it does that, if you think about it, inside of the engine somewhere, there's a set timeout utility, and he gets a little callback called see me, and he'll execute him at some point. He's executing your function well outside of his lexical scope. But your function still remembers the lexical scope and that's because of closure. In this particular example, what if bar were to change, like the value of bar, were to change within, the hundred thousand millisecond. That's exactly what I was meant by saying it's not like a snapshot, it's an actual live link back to the actual scope. So if you changed it between the time you set it up and the time the timer fired, it would access the current value at that moment. Another example, if you're familiar with any kind of frameworks that do click handlers, you set up your click handlers and your click handlers are able to remember something about their lexical environment, that's entirely because of closure. Closure is a necessary mechanism for a language with first-class functions as values, to be useful. If functions could be passed around with their values, but they couldn't remember anything about their lexical scope, nobody would pass functions around. The only reason why we find this useful, is because they implicitly have this capability called closure. This, again references, it doesn't matter how many functions have a closure over the scope, they all have a closure over the same scope. You can think about scope, by the way, this is another way to kind of process it in your brain. You're probably familiar with the idea of garbage collection in JavaScript. Maybe, that might be a little bit confusing to you, but let's just say that in JavaScript, if you keep a reference to an object around, that object doesn't get garbage collected, so if you had 10 different references to it, and nine of them went away but one of them was still there, it still wasn't garbage collected. Soon as the 10th reference goes away, now the engine can garbage collect it. The same similar kind of mechanism is at work with your scope. When you execute a function, it creates a scope object. If there's anybody that gets a reference to that scope object via closure, that scope doesn't get garbage collected when the function ends. It keeps the scope around, and it can continue to keep modifying it and accessing it, as long as there's still one function, at least one function with a closure over the scope, that scope doesn't go away. So here we've got two different functions, the one on four through six, and the one on seven through nine. Both functions have a closure over the same scope. Which means when the first one runs, he updates bar, when the second one runs, he updates the exact same bar. It's all levels, it's not restricted, so, whatever the entire nested deep level is, here we have a bar referencing one level up. This bar is now referencing two levels up, the exact same bar, and this baz, is referencing a different so it maintains the entire scope, however nested and deep it is, for as long as is necessary. That is what we call closure. Questions so far about closure? Alright, now this is the canonical example for illustrating how closure works. And it references this idea with loops, and with functions inside of them. The spirit of this exercise is that I would be able to loop through and have, you know, at the one second mark have it print out i1, at the two second mark have it print out i2, at the three second mark have it print out i3, i4, and i5. I want each one of you to click the code me icon down in the bottom left, and I want you to tell me what it prints out in your console. What are you getting it to say? Six sets of six. It prints out six, five different times, right? So, the reason for that is what's wrong with our understanding of closure and that's why we show this example, to kind of explain, when closure's not behaving the way we want, it's because we have an incomplete understanding of what the closure would really mean. We have here this implicit idea, normally I would kind of belabor this as a big exercise, but just to keep us on track I'll just go ahead and kind of shortcut to it. That what we have here, is we need to ask ourselves what's missing from this example, that's preventing it from working? So the way we could ask the question is, if I'm getting i66666, well we can explain why that happens pretty clearly. It's that the i at the end of the loop ends up a 6. And so when these functions run 1000, and 2000, and 3000, obviously i is already 6 by the time those functions are running. But what's really wrong is why don't we have five different i values? In other words, why don't we have five different i's? Because for some reason, the way our developer brains work, when we did this loop, we seemed to think that these functions were getting a whole new i for each iteration of the loop. But they're not, are they? They're five different functions that are closing over the exact same global scope. It's no different than if I wrote the set timeout one after the other, five times on top of each other like I did a couple slides ago. Something about the loop confuses us into thinking that there's something more magical going on. This is five separate anonymous functions that close over the exact same scope, that is the global scope that only has one i in it. So we can ask the question, what's missing? What could I do to this piece of code, that would allow it to have a different i for each iteration? To have a whole different scope for each iteration. And that solution is typically the IIFE. Remember how functions create scope. So if we were put an IIFE inside of the loop, each loop would get its own i. And the functions inside of them, if you were to try this code, if you click on the code man you try it. It will now run correctly, it'll print 12345. Because we have a whole different scope created for each iteration. So each one of those functions is closing over an iteration scope rather than just over the global scope. Yeah. If you used let, would it-- We're getting' there. Ok. Wait just a minute. This is the canonical solution to it, is that you put an IIFE inside of a loop. Because what was really missing, was that we wanted a scope for each iteration. Everybody with me on that?
More Closure Examples
What if we used that let keyword? Now, the way it looks is that that let keyword is binding an i to the for-loop. But actually, there's a very special behavior in the spec that says it's binding the i not just to the for-loop, it's re-binding that I for each iteration of the for-loop. So if we started using let i, all of the sudden it magically creates a brand new i for each iteration that our functions will duly close over. And it'll just work, without needing to insert the IIFE. So that's a pretty cool thing that block scoping plus loops kind of solves that canonical problem of not having enough scope in each one of our iterations. This would be, I don't think I have this slide here, but this would be no different than if we had said, 4 var i=1, and then inside of our iteration loop we had said something like let j=i. We would have been creating a j, brand new for each iteration. Like if on line 1 1/2, I said let j=i, and then instead of referencing the i's here inside of our function, we referenced j, we'd obviously be referencing a j that was created for each iteration. So we could do it that way. Turns out there's an extra special behavior that lets the for-header do that automatically for us. Yeah. So then if you used one of those transpilers to run let on a DS5, and on a long-running loop like through 10,000 elements, it's still got to crank out 10,000 exceptions to do that catch thing. Could that be an extensive performance hit? Because the left thing is currently a catch block, from a thrown in exception, see it'll generate, like 10,000 exceptions and catch them 10,000 times, right? So are you saying that if I use let i, regardless of the transpiler, you're saying if I use let i, is it a performance hit 'cause it's creating a whole bunch of i variables, is that what you're asking? Because when you're writing the DS5, the trick was to run it in a catch block, right? Mm-hmm. And to get there you had to throw in an exception, right? Mm-hmm. So you got to throw an exception 10,000 times, in a loop that loops 10,000 times, right? Yeah. 10,000 stack traces, right? Yes. I don't know, I-- So, if you put this code, as is, into the Google traceur-compiler, that's exactly what it would do, is it would put a try-catch inside of the iteration, it would run each one of the 10,000 iterations. If, on the other hand, you did something like I would suggest where I don't want, like let's say I was in a situation where I didn't need a new i, but I still wanted it to be block-bound. Then I could create an explicit block, using letter syntax, around the for-loop, and then it's just one try-catch instead of for each iteration. So, yes. The bottom line is that ES6 will have the capability to optimize that binding. Our transpiled ones will take a performance hit, but it's really kind of like, do you want the benefits of block binding, not do you want to take a temporary performance hit, 'cause eventually the performance hit will go away. But yeah, it's a good point. Alright, now given everything I've taught you about closures I want you to tell me if this particular example is an example, if this particular code is an example of closure. What we have here is we have one of those IIFE's running, you can see I have an IIFE running. I have a foo that's pointing at this object that gets returned, and this object keeps a reference to this variable inside it, and outside of my function, I'm able to reference something from inside of the function. So, by virtue of our definition of closure, is this closure? No. Why not? I think there would need to be something returned from an inner function. Or a function, or, I just don't know, but it doesn't feel right. (laughter) It doesn't feel right. Yeah. I wish that was a good enough answer, for like the real world. (laughter) I know, man. No, boss, I don't know why, but it just doesn't feel right. Something smells wrong. You got to give me an answer as to why, you got to defend your position. I would take the opposite position. You think it is closure. Yes. Why is it closure? It's accessing a variable it doesn't have access to its scope normally. Ok, let's go to the definition that I gave you for closure. What was the definition that I gave you? There were two characteristics for that definition. You have access to the lexical scope. What was the definition, can somebody go back and read it to me? It remembers its lexical scope-- What remembers its lexical scope? Function. When a function remembers its lexical scope, even when the, Function. Function is executing outside its lexical scope. Is there a function who is remembering his lexical scope? No. No. Because we didn't transport a function out. This is kind of what you were trying to articulate. There's no inner function here, that's being transported out. We are keeping an object reference around, this code works, you can run this code and it will work. We're keeping an object reference around, but we are not having a function keep a reference to a scope. So by definition this isn't closure, it is object references but it's not closure. Does that make sense? It's got to be a function being transported out.
Module Patterns
Let's take a look at some practical usefulness for this closure mechanism, and how we use this. You remember I talked about IIFE 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 executed. Does not have to be an IIFE, but it does have to be an outer function that gets executed. Ok? In this case it is an IIFE, 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 that I'm going to return, foo is going to end up pointing at this object, all of the 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 closure capability to access the internal state, and that makes a module. 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. So if I had 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 IIFE, 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. So the outer function is like a class, and the inner functions are like-- Not like a class, I hate it when people call it classes. 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. Ok. It's not a class. People like to think these things are classes. We'll get there, why it's not a class, yeah. If you just returned a function instead of an object with a var function, that would still be-- Still be a module, that's exactly what jQuery does. jQuery makes the dollar sign is the public API and it's just a function. There was a question about what the two characteristics of module patterns were, that somebody missed something. 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. Alright 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, so you better get familiar with the classic module pattern, because your exercise calls for you to do exactly this. Ok, 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 returned back is kind of like a public API. Rather than returning 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 I do that is both functional and stylistic. Stylistically, it's kind of like when I talked about my IIFE where I passed 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 dot, 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 can add and remove methods. 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. 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. Does that make sense? So I call 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, as I said, suggested to you, you should go home and wrap your code in IIFEs. 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. Alright, 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've 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. It might bear, any relationship that it bears to existing loaders is entirely coincidental. I call mine define, but guess what it does? It takes a name for my module, and it takes a function that returns back an object. That should look awfully familiar. 'Cause 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 on 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 special, magical, black boxes of goodness. They're not really doing anything special. They're just executing a function and assigning the return value for you. At their core, ok? So I could make one of these, in fact, in my book, the Scope & Closures book, I show you a little 30-line implementation of a module manager kind of thing that does exactly what I just suggested. And finally the future, or the ES6 module pattern. As of ES6, we're getting, I'm sorry, there was a question, yeah. Yeah, on a previous couple slides, with all the var foo, and the define for foo, are you using an anonymous function? James L. would like to know why you're using an anonymous function. 'Cause 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 more. In correction code, would you recommend a different practice? 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. And another one, from Oliver, he was talking about Christian Haleman evangelizing the module pattern, and if this is basically what he was talking about. Yeah, if you're talking about the module pattern in JavaScript, that's what this is. Absolutely. It's the most, if it's not one, it's two, most common patterns in all of JavaScript. If you are not aware of it, if you're not using any of your code, go home tonight and put module wrappers around your code, because it immediately creates more organized and more sane code to maintain. Alright, 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 IIFE, for instance. And instead of returning things, we used this new keyword called export. And you can call export one, or 100 times, 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 file 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 things. 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. But when a file gets loaded using this mechanism, it will treat the contents of that file like they're a module. So this is syntax that's supported as of ES6, I will be 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 the spec, yeah. If foo.js defined two functions to be public, like export function bar, export function foo two or whatever. Values. Yeah, can you import just two of them on the same line, import-- Yep, yep. Yeah, ok. Yeah, you can do the commas, there's a wild card, so you can import all of them. Yeah. 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 of the module pattern.
Quiz: Closure
Let's do a quiz. What is a closure and how is it created? In other words, I want you to give me back my definition. What is a closure, and how is it created? A closure is a function that can be called, that keeps its lexical scope when it's called somewhere else. Exactly. A closure is when a function remembers and accesses its lexical scope, even when that function is executed outside of its lexical scope. Ok, how is it created? When an inner function is transported outside of the outer function. Right? How long does its scope stay around? Until there's no longer any references to it. Yep, so what we basically said was, a closure is kind of like a reference to a hidden scope object. So as long as there's some function that still has a closure over the scope, that scope's going to stay around. But as soon as that closure goes away, scope can get garbage collected. Why doesn't a function callback inside of the loop behave as expected? What was wrong with that little for-loop with the set timeout inside of it? It wasn't actually creating its own closure? Yeah, there wasn't a variable created per iteration. Yeah. We thought that somehow magically it was, but it wasn't. How did we solve that? What was the canonical way that we solved it? The IIFE. Putting an IIFE inside of the iteration, that did it. Also, the other solution? The let. The let keyword, right? Putting a let keyword on the for header, or inside the for-loop, that also creates scoping per iteration. How do you use a closure to create an encapsulated module? There were two characteristics, what were they? It has to be wrapped by a function. Has to be an outer-wrapping function, that's the first one, the second one? Return one or more functions. Return one or more inner functions that have a closure over the scope. What are the benefits of that module pattern? Why is that beneficial? Create private and public. Hiding stuff, the principle of least exposure, hiding things, having a public API. It's the idea of not exposing inner details that you don't want people to accidentally rely on, undocumented features, all of those benefits. Can anybody think of a tradeoff to the module pattern? There's a couple of tradeoffs. One tradeoff that some people, it's not a tradeoff in my opinion because I have a different opinion about what testing means, but some people don't like the module pattern because it hides a bunch of stuff, and it makes that inner stuff hard or impossible to test. One of the benefits of having everything public is that everything's testable, right? So we have this idea of unit testing, and theoretically, unit testing says we should unit test every single function. I disagree with that definition of unit testing, to be personally honest. I think a unit is the smallest indivisible unit of code. So if a module has 100 inner functions, and only one public API, there's just one unit test, and it's for that one public API. That's my own take on testing, but some people think it's a downside that you have all that hidden stuff and you can't individually test any of the implementation details. So that's one tradeoff, anybody think of a different tradeoff? It might've been a little bit subtle, so I'll help you. Every time I create a new module, remember I have this function that can churn out a new module? Am I creating a whole new copy of all that internal functions? So let's say I had one little module factory, and I wanted to create 1000 instances of my module, out of 1000 copies of all of its functionality. So I'm creating a whole bunch of extra copies. We will see in the next section of our discussion, we'll see a way that that particular drawback can be addressed.
Exercise 2
Alright, exercise two. I've listed it at 20 minutes. It shouldn't take you more than five. Because you're going to write less than eight lines of code. But, as they say, it's not, as they say, the important thing is which eight lines of code do we write? So, let's open up exercise two. You can open up the README, and the js file. I'm going to open up in a browser the fixed version of the code, because I want you to see what it's supposed to do. Well actually it doesn't matter. It doesn't matter the fixed versus non-fixed. Let's just look at exercise two. I'll open up the HTML file. It's a simple note-taker app. We have built in, you know, you can click on the notes, and highlight them, you can click out. You can add stuff, and, you have a little help dialogue that tells you what to do. So it's a simple little note-taker. You're not going to add any functionality to this app, but what you are going to do, is use the classic module pattern to organize the code better. So if we look at ex2.js, it's a whole bunch of global functions with no organization whatsoever. And what I want you to do, is using what I just taught you about the module pattern, go back and turn this into a well-formed module. And I explain how to do that. You'll have two methods on your public API, one will be called a nit. One will be for loading in data. You'll create yourself a little module, API, and then modify the code to do that. So, again, you're literally writing, like less than 15 lines of code. If you find yourself doing lots and lots of coding you're doing it the hard way. It's very simple, but go back to your slides where I discussed the classic module pattern, the characteristics of a wrapper function, and a return value and all of that. That should be more than enough to get you going. I'll give you guys maybe eight or 10 minutes, and then we'll come back.
Exercise 2 Solution
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 README you'd see, this is not data we want to internalize into our module, so, we're going to want to take that stuff, kind of probably move it down to the bottom, 'cause we're going to 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 going to be our module instance, 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, 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 going to want to do something like, publicAPI =, and have some object here. And then we want to return that public API. 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. Now I need to actually implement that function, so loadData, the purpose of it is to take an array of records, and add them to our existing internal array. So we can say, you know, data, and we can say notes, which is going to be our internal array, is equal to notes.concat, data. So we want to keep a internal notes array that will start out initially as empty. And then we have this loadData function. Now that's all I've had to change, and I've created myself a module. 'Cause you'll notice that I have a NotesManager, variable, it's an instance for my module, it's getting an object that has two methods on it, init and loadData. 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. 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. But we're loading in this data, pushing that into our NotesManager, and then calling the NotesManager init when the dom is ready, using jQuery's dom ready event. Yeah. This is kind of a weird question maybe, but your IIFE up at the top, you're saying var NotesManager = anonymous function. I you were to say a function and name that function, capital N notes, capital M manager, what does NotesManager refer to in the global scope? 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. Ok. 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 inner scope you would reference a NotesManager, which referenced the function, but in the outer scope NotesManager would reference the return value from the function call. Right. So that would be kind of a confusing thing, but you could certainly name this thing like, you know, ModuleFactory or whatever you want to name it. Ok. The other thing to point out, does everybody see so far, any questions about how we constructed our module? 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. Couple 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? 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 = NotesManager. And yourNotes = NotesManager. And I can make multiple ones of those, by simply calling the factory multiple times. 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. 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 functions, so, there might be some downside if you were legitimately going to 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 pattern works well. One other thing just to point out real quick, I won't belabor it, but, there is a mention in here, this .4 down here. Talks about the structure of our code with relation to our dom references. So you'll note, inside of my code, I've got a whole bunch of manual references to dom IDs. 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. And it's not that difficult for us to abstract some of that away, so one quick pass at how I might do something like that, is I might have, 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. 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, I pass in an object that has that selector in it. 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. 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 of code. Alright, any more questions on exercise two? 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 myNotes 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. 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. Hopefully that answers James's question on the chat room.
Object Orienting
Prototype
We now are going to transition into discussion of Object Orienting which is our next major thing in JavaScript. So we've spent the majority of the day so far talking about the scope and closures then this keyword. Now we're going to transition into a discussion of Object Orienting which is the other major area of JavaScript that has a lot of confusion, a lot of complexity to it. We're going to try to rip away all of that complexity. I'll give you the fair warning that where we're headed, what I'm about to teach you over the next hour or an hour and a half or so with this Object Orienting stuff is significantly divergent from what the vast majority of the JavaScript community believes about the language. This is my own personal take on how I think it's a much better way of thinking about JavaScript, but it requires you to actually have a very different mindset because you come to the language most likely with the assumptions about the way classes work and you try to make JavaScript work with classes, and the punch line is that we're headed towards me teaching you that there are no such things as classes in JavaScript, and that we have to have a very different, not just a different syntax but a very different design pattern for our software, and that's where we're headed, okay? So we're going to first, I was going to talk about these common OO patterns, there's a couple of slides there where I show off the singleton pattern, the observer pattern. They probably speak for themselves so just in the interest of time I'll probably skip over those slides and we'll go right into our discussion of the prototype mechanism. I'll skip over a couple of these. If there are any questions and we have some time at the end I can go back and answer any question you may have, but just kind of showing some ways that you might implement common design patterns with JavaScript. Any discussion about Object Orienting, JavaScript requires us to discuss the prototype mechanism. Every single object when it is constructed, it's built by a constructor function and really to be most accurate, it would be accurate to say that it's built by a constructor call. And I already showed you how that works. Remember when we call New with a function, it creates an object. That's not the same as instantiating a class, it's just that it constructs objects. As a matter of fact I would push back on nearly two or three decades worth of precedent. The fact that we have languages like C++ and Java that are called object-oriented, those are kind of a misnomer because those languages should have been called class oriented. In fact there's only two languages today, right now, and one of them you know about, JavaScript. The other one you may not have even heard of, that language is Lua. Those are maybe the only two languages in existence today which actually deserve the moniker object oriented, because they're the only languages where you can actually create an object without a class. Now all the other languages are all about classes, and classes getting instantiated in the objects. Unfortunately that ship has long since sailed so we can't really do away with that object oriented moniker but it's an inaccurate term for what's happening because these constructors in JavaScript are not building from classes, they're just creating objects out of thin air. But every single object that gets built, gets built by calling one of these constructor calls, either directly or indirectly. And each time one of those constructors is called a brand new object is created, so it lends itself to you thinking that there's an instance happening when in reality it's not actually an instance. It's often said that a constructor makes an object based on that constructor's prototype, and it is that phrase "based on" that I take most objection to, because the phrase based on begins to imply something about the language that's not actually true. It's something that is very true in all the other class-oriented languages that you're aware of, C++ and Java and all those other ones, but it's not true of JavaScript. Based on implies that we take the prototype and we stamp out a copy of it. Though that's the way it works in class-oriented languages. When you have a parent class and you instantiate that parent class, there's a copy of the behavior from the class into the instance, and once the two have been separated there's no more relationship between the two. I have an instance that was a copy of a parent, but that's not what happens in JavaScript. So the phrase based on really leads us down the wrong path. I would say it's more appropriate to say that a constructor makes an object that is "linked to" the constructor's prototype. And there are people that will say these are one and the same, and I would push back and say these are fundamentally different mechanisms. So what do we mean by linked to? You might remember when I discussed the new keyword, I talked to you about those four steps, and I told there was point two, that it was of the things that it did is that it linked to an object and I said put an asterisk there, because we're going to come back. Now we're going to take about what that linkage means. What do we mean that a constructor is making objects linked to some other prototype object? What does that really mean?
Prototypes Explained, Part 1
Here's one of those places in the code where I'm going to put up this slide and I'm going to spend an awful lot of time, maybe 30 minutes or more talking about this slide, and this is the point by the way where I need to bring over the whiteboard because this is my long diagram. What I am going to do is I'm going to draw for you a diagram of what occurs when this code is interpreted by the JavaScript engine. I will present this diagram in a few slides, you don't need to redraw this yourself, but it's instructful for me to show you how the diagram comes about based upon each line of this code. So that's what we're going to do here. And what I'm going to do before we even get to line one, there's already something that has occurred just as a function of what's happened with the JavaScript language. I'm going to draw this dotted line here. This dotted line, everything on the top of this dotted line is going to indicate stuff that's already happened before we even get to line one. Now what I'm going to do is I'm going to represent objects as squares, and functions as circles, okay? Just of my own convention. So, before we even get to line one of this code, there is a function which I'll represent with a big circle, there is a function who is called Object, capital O Object, and you're probably familiar with that, that exists in the language. There's a function called Object. And there is an object, there is a square, there is an object who this guy is linked to, and this guy doesn't really have a name it just has this kind of weird arbitrary label. The arbitrary label that he has is object.prototype, all lowercase. object.prototype points at this object. Now on this guy is stuff like to string, and value of and several of the other things that you're probably already familiar with that are built in the language. But they all come from this guy. Everybody with me so far? This exists at the beginning of every JavaScript program, it's part of the environment that gets created. Now let's talk about line one. What is line one going to create for us? Well line one, I'll come over here, line one is going to create a circle that we give the label foo, so function called foo. It's also going to create an object that we are linked to and it's going to have that same arbitrary name .prototype, all lowercase letters, .prototype. In addition to there being this connection, there is also a connection in the opposite direction. This object has a property on him called .constructor. Now, most people see the property name .constructor, and they immediately think that .constructor means was constructed by, in other words this object was constructed by this function. Not true. It is one of those many misconceptions you're going to have to set aside. The word constructor is literally just an arbitrary word. It could have been abracadabra. It doesn't actually mean anything at all about was constructed by. You just have to kind of set aside that idea. But there is this dual linkage here. There is a .prototype that points to this object here and there is a constructor linkage back to the foo function. That's everything that we get as of line one. Everybody with me so far? Now we're going to skip over line two for now we'll come back to that. What happens with line four? You notice that we arbitrarily start adding properties to this arbitrarily named object foo.prototype. It's this guy that's just hanging out here. We start adding properties to him. So we add an identify and that's like doing this it's like adding identify. We put identify directly on the object. Doesn't matter that he's a method right now, he's just a property for all we care. We're putting identify directly on the object. Now let's skip over line five we'll come back to that. Let's do line eight. Line eight says new foo, okay? Remember I said there were four things that happen when the new keyword gets called with a function call. Does anybody remember what those four things were? Brand new objects gets created and I'm going to create a brand new object, okay? Brand new object gets created. What's the second thing that occurs? Object gets linked, so there's a linkage that occurs here which I'll explain in a moment. What's the third thing that occurs? The context gets set to this. When we're calling the foo function that this keyword will be pointing at this particular object. Sorry for my poor drawing skills. When we execute line two and we say this.me when we add a property to me we're putting a property directly on this object. Does everybody see that? Doesn't matter what its value is we just put a property on it. What's the fourth thing that happens when we call the new function? It returns this which then on line one when we assign to A1. We give the label to that object A1. So everybody follow how line eight occurred? You notice we haven't talked about classes, or inheritance or instantiation or anything. It's 'cause none of that stuff actually exists you've just been lied to that it exists. Okay, line nine. If we understand how line eight works then line nine does the same exact thing. It creates another box that's also linked that also gets a me property and we give him the label A2. Does everybody see that? Now let's look at line 11. Line 11 says A2.speak. Where does that speak property get added? Right here. Everybody follow that? Now at this point if I were say something like A1.speak, what would you expect to happen? It's not there, right? Because it's quite clear that it's on A2. We're going to see how A1 and A2 can reference identify but for right now it's very clear that A2 got a member directly on him on speak. It wasn't added to anything in this prototype, okay? Let's look at line 15. Says that there is an A1.constructor. Look at this object and tell me if you see a constructor property on it. It comes from the prototype? There is no constructor property on this object. I would say better than 99% of all JavaScript developers think that there's a hidden constructor property on the object. Just because it's automatically created by because it was 'constructed by' foo therefore it must have a constructor property. It doesn't have it. When we say A1.constructor and it doesn't exist, what happens? It goes up the prototype chain until it finds it. It's going to go up the prototype chain. This is where this mechanism, this prototype mechanism starts to look a lot like a scope model. And it's the whole reason I set up that comparison between the two models. Because what we're going to do is we're going to say A1.constructor does not exist. We're going to then going to traverse the prototype chain. These linkages that I talked about these are called the prototype link. In the spec speak prototype is referenced by saying bracket bracket capital P Prototype. Then you can see quite right away why that's confusing because they call it bracket bracket capital P Prototype and they call this thing .prototype and grammatically it's hard for you to tell which one I'm talking about. I'm going to distinguish verbally when I say these things by saying bracket bracket P or .prototype. That's how I'm going to distinguish between the two so you know what I'm talking about. These linkages here are called bracket bracket P. They are internal linkages. They don't exist publicly. They're just an internal link between the two. And this is a prototype chain that we can traverse. When we say A1.constructor, there is no constructor so we walk up the prototype chain and we ask for this guy. Does this guy have a constructor? Yes. So we can say .constructor and put him here. By the way let me pause for just a moment. I forgot to draw something earlier. You remember on line one when I was drawing this? I forgot something. There is a linkage from there to there and that linkage is also bracket bracket P. That happened as of line one I forgot to draw them, okay? We have this bracket bracket P. When I say A1.constructor I'm delegating up to this guy who does have a constructor and he ends up being foo. At this point, you would be forgiven if you were under this misconception that A1.constructor pointing at foo means foo was the one who constructed me. 'Cause that's kind of a misconception. Actually a lot of a misconception. .constructor doesn't mean I was constructed by it just happens as a happy accident to point to the location that we would want it to point to here. We'll see in just a few slides why that assumption goes completely away under other circumstances. A1.constructor points to foo, clearly A2.constructor will point to foo, everything feels good.
Prototypes Explained, Part 2
Now what about line 17? I started referencing this bizarrely named property __proto__. Let me just stop right here and say a couple of years ago the JavaScript community was trying to come up with a better name for that 'cause nobody wants to say underscore underscore proto underscore underscore. We came up with a better name for it kind of like we came up with iffy. The name for that underscore underscore thing is dunder kind of like Dunder Mifflin. If you want to be a cool kid in JavaScript the way to properly pronounce that property name is dunder proto. That's the third thing that I will say and keep that distinguished from the other two .prototypes is that underscore underscore proto I will pronounce as dunder proto, okay? a1.__proto, is there a dunder proto property on this guy? No, so what's he going to do? He's going to come up to this object. Is there a dunder proto on this guy? No. He's going to come up to this guy and it turns out there is in fact a dunder proto on the built in object.prototype. When we say a1.__proto we are calling this property. It turns out it's not actually a property. It turns out it's a getter function. It's kind of like making a function call on line 17. Guess what that function call does? It returns the internal prototype linkage of whatever the this.binding is. At the call side on line 17 we pretend that there are some parentheses there on line 17. When that's calling a function what will this keyword be inside of that function call? A1. A1, which is what we want it to be. It's going to return the internal prototype linkage of A1. This bracket bracket p is the internal link. We can say that the public link for it is underscore underscore proto or dunder proto. Everybody following so far? This is a public property that references an internal characteristic. Now the problem with dunder proto is that it's never been standardized. It was invented 15 years ago by Mozilla because they wanted some way to publicly expose this internal property but it was never standardized. Unfortunately, even though it was not standardized everybody adopted it. Safari and Chrome and all the other browsers they all came out and adopted it except from one browser, anybody guess which browser? IE. Internet Explorer said, "No, no, no. "We're not going to put a dunder proto on there, no, no." In a shocking twist of irony Internet Explorer Microsoft who was the king of adding proprietary nonstandard stuff to JavaScript said, "No, no, no, dunder proto is not standardized. "We're not going to add that to the language "until it gets standardized." And they could never agree and the TC39 committee had to standardize it, so it became a defacto standard except for IE. Which means it wasn't really reliable because if you add any code that needed to run an IE couldn't use it. There's a lot of people that really hate the dunder proto. I'm not advocating for or against it, I'm just telling you that it exists. But it's nonstandard until ES6. It's finally been standardized. That doesn't mean that you should use it. It just means they agreed that it's finally about time if everybody's been using it we ought to go ahead and standardize it. And guess what happened immediately after TC39 publicly said we're going to standardize it? IE dropped it into IE 11, so it exists in IE 11. There's been a request from a couple of people and they checked if we could pause whenever we're done drawing this drawing and have it on full-screen so that it could be screen cast. Or if you have a drawing of it online. I don't mind it but I've already said this exact same diagram in a better form comes like three slides from now. I'm only drawing out the diagrams so you see how it fits with the lines of code but I'll provide you these diagrams in a few slides so don't worry. Thank you. This a1.__proto points at this object and we can see that that's the same thing as Foo.prototype. Everybody see that? a1.__proto is the same thing as Foo.prototype. And both a1 and a2 point to the same object. Everybody with me so far? Okay, moving on to the next line. It's the same code but I want to illustrate one other thing. This dunder proto not being standard until of course ES6, back in the ES5 days that was back in like 2009, 2011 they said we do need to provide some standardized way for you to access the internal prototype characteristic. We're not going to do it with the dunder proto but we need to provide some way to do it. As of ES5, they added a mechanism that you see right here on line one get prototype of, Object.getPrototypeOf is a utility that will extract the internal prototype characteristic. So if we ask for the characteristic of A1 it's going to give us this language. So that was added as of ES5, which means it was standardized as of ES5 which means IE put it in as of IE9. While you didn't have dunder proto you did have Object.getPrototypeOf as of IE9 which is a lot better than IE11 but it still leaves IE8 and below totally out in the cold, what do we do about IE8 and below? We then come to the third and final way that you can, in a very crappy and hacky way, get at that linkage. And the way that we do that is what you see on line 18. We can do this really crazy indirect approach, we can say something like a2.constructor, which gets over here to Foo, .prototype which gets back to the object. So a2.constructor.prototype will also get us to the object. Now, here's the problem with that. Both the constructor property and the prototype property are writable properties. They happen to default to pointing where we show them here, but guess what happens if either or both of them gets overwritten. Then that third way of doing it is completely out the window, it's totally non-reliable. They're not special properties in some sense that they're protected or somehow forced to be the right thing. They're just properties and they can be changed. But those are our three ways of getting it. We have dunder proto, which is available as of IE11 and standardized as of ES6. We have Object.getPrototypeOf, gets us that same linkage that's available as of IE9, standardized as of ES5, and we have this crappy ES3 way of doing it, .constructor.prototype.
Prototype Linkages
Now what about this linkage that we've been talking about? What happens if I call a1.identify? What's it going to do? Is there an identify function on a1? No, so it's going to say a1 dot, and it's going to traverse the prototype and say there is an identify on this object. Yeah, beautifully there is. So, here's the first benefit that we start to see of the prototype linkage is that we have this ability to delegate to a different object to handle a method call or a property reference. Notice how we have a1 and a2, there is not multiple copies of the identify function like there would be in the module pattern. What happens if we created a thousand of these, a1 through a1000, and every one of them was linked to this one? There'd only be one copy of the function. And that function we see right there on line five, it references this keyword. When I say a1.identify, what is the this.binding that would be inside of that call? a1 which is what we want it to be, so it's going to get the me that a1 has. If we say a2.identify what is this key word going to be? a2, exactly like we want, and the same for a3 through a1000. So then this keyword ends up being a really nice mechanism for us when we're dealing with delegation of the prototype chain only when we behave by the rules. We'll see here in a moment how it can get bad but if we behave by the rules, that binding ends up working really well for us. Now, what happens here on this I have slightly different code, you see a1.identify on line nine. What happens if I then on line 11 do a1.identify equals and I add a property? Where does that change, does it change this guy? No, it actually adds it directly here, which, depending upon your mindset, may or may not make much sense. But it didn't change that guy even though a1.identify as an RHS reference would have delegated up and called that function room when we say a1 dot identify we're not replacing that guy, we're adding a new function directly to a1, so now when we call a1.identify on line seven which one are we calling? This guy or this guy? We're calling this guy's instance. This is called shadowing, remember I talked about variable shadowing in Scopes? Same thing can happen with prototype chain. Properties on the prototype chain can shadow each other. Now that I have a shadowed version of this identify whenever I say a1.identify, it's always going to find this guy, it's never going to find that guy. Now, here's where things start to break down because class-oriented coding, the design pattern of classes tells you to create parent classes and child classes that have method names that are the same, and it says create an abstract version of a method on the parent class, and on your child class create, override that version of it and be able to do things like relative polymorphism where you call super, to call one level up the chain. That's the whole, I mean that's of the major benefits of the design pattern of classes, is the ability to name your things the same thing at multiple levels. But here we see that it actually creates a whole world of problems, because look what happens on line 13, if inside of this guy I did want to somehow reference that guy, I can't say this.identify because that's just going to be recursed to myself. How do I do it? I do this crazy thing that I call, you know, sort of explicit polymorphism, I have to say Foo.prototype.identify, to manually find this method. And not only that I have to say call this because I want to make sure that when that guy gets called a1 is the this.binding. So I do this crazy crappy syntax on line 13 to accomplish the relative polymorphism that the class design pattern would call for. JavaScript as of this moment doesn't have a mechanism to enable that. If you choose to create the shadowing, if you choose to create multiple levels of your prototype chain with the same method name the way classes tell you to design your software, you are asking for having to do crap like that. If, however, we had called this guy identify to or anything else except for identify then inside of that function we could have said this.identify and it would have delegated up to that guy. If we use different method names, everything works beautifully. Let me show you that. Next slide shows us what I call super unicorn magic because as you'll see here I have a Foo identify and a Foo.prorotype.identify and a Foo.prototype.speak. On line 16 when I call a1.speak speak gets called through the delegation on Foo.prototype. But what does speak do? He says this.identify. What is this keyword inside of speak? a1, so it's like saying a1.identify. Does a1 have an identify? No, but he steps right back up the prototype chain. The nice thing about the way that this mechanism works is it's always rooted at that call sign. That this keyword always references the call sign. And that's always what we want unless we do that crappy shadowing thing. The takeaway that I will give you just at this point until you understand what I'm going to suggest is the alternative. The takeaway that I would give you is it's your choice whether or not you do shadowing and whether or not you design your software to expect the same method name at multiple levels. If you avoid shadowing, everything works with super unicorn magic. It's just always the right thing. If you decide to do shadowing, good luck with all that extra crappy syntax, okay? Yeah? I mean the end result is you want to delegate a function that can be shared across multiple objects. Maybe yeah. Not necessarily multiple objects but yeah. Well if you have ten a1 or 10a objects you want to share identify. Yeah. But I'm suggesting that delegation the way we're talking about it could be useful even though there was only an a1. It doesn't have to be multiples but multiples are certainly useful. Where, we're going, when we get to the punch line of all this where we talk about delegation as the design pattern as opposed to classes, I'll show you why I think that's an important thing to uncover. But I'm just right now just exposing the mechanism and trying to layer on to you and show you why classes don't fit well with this mechanism. We've spent the better part of now almost 19 years since JavaScript was invented trying to pretend that JavaScript has classes and we've created every manner of JavaScript library and syntactic sugar that we can invent under the sun. What it all boils down to is that these are not copy mechanisms these are prototype linkage behavior delegation mechanisms. What we finally do is we finally come back to this diagram, the diagram I gave you before. We should be well versed in how lexical scope works on the left-hand side, but we now understand how this plus prototype describes what happens in the right-hand side. This keyword tells us which building to go in to, which address of the building downtown to go in to. The prototype mechanism tells us how we're going to find properties if they don't exist on the direct object. When we say a1.identify it first looks in the first floor of a1 and if doesn't find it there it goes up one level, traversing up one level of the prototype chain, going up one floor of the elevator. Goes to the second floor, goes to the third floor, goes to the fourth floor. Keeps going to the top until it gets to the top which is object prototype. It's the analog to the global scope when we're doing lexical scope. Remember these two mechanisms while they operate sort of similarly and that both of them have elevators, the elevators do not cross over in any way, shape or form. They're two orthogonal mechanisms.
Prototype: Objects Linked
Here's why things start to get complicated with respect to that .constructor and when we start layering things trying to model things as classes, okay? I have a function Foo that's representing a class and mostly it's just a class because I use the capital letter F. But I start adding things like an identify to its prototype and then I want to create a child class that I call bar. And theoretically that child class bar is supposed to inherit from or extend to the parent class Foo. How do I accomplish that? When line 12 shows you how you would most likely accomplish that because what you need is you need for bar's prototype to extend foo's prototype. Or in this case what you really need is for bars prototype to link to Foo's prototype. How do we accomplish that? Well, we could do as you see there in the comments on line 11, we could do bar.prototype equals new Foo because that would create a brand new object that was linked to Foo prototype like we want. But that would have the unfortunate side-effect of actually calling the Foo function and adding properties like this this.me to it which we don't want. So we can't really call the constructor. The other way we do it is this utility called object.create, okay? That was standardized as of ES5. There is a simple three line polyfill which I'll show you later . That allows you to use it before ES5. But object.create essentially does the first two of the four steps that I taught you that the new keyword does. What were those first two steps that I told you? Create a new object. And link it. It does those two but it does not do steps three and four 'cause there is no constructor for it to bind to these two and there is no need for it to return it. It does the first two which is what we want and it doesn't do the last two which is what we don't want. Everybody follow that? Okay. Object.create is a nice useful helper for us. It'll create bar.prototype that is linked to Foo prototype. We can add things to bar prototype like bar.prototype.speak. And indeed when we say b1 equals new bar and we say b1.speak, guess what's going to happen? It's going to delegate from b1 up to bar prototype and it's going to find the speak function and it's going to see our this.identify. What is this keyword going to be? It's going to be b1, right? We're going to say is there a b1.identify? No. We're going to delegate from b1 up to bar prototype. Is there a bar prototype identifier? We're going to keep going and we're going to go up to Foo prototype. Is there a Foo prototype identifier? We're going to execute Foo prototype and it has this reference. What is this reference going to be? Still b1. Super unicorn magic that this keyword always keeps pointing to the thing we want it to even if we've delegated 15 levels up the prototype chain. It's a really powerful and useful mechanism. But there are some really subtle problems when you start trying to think about this stuff as parent and child classes. The first one is something I noted here on line 13. And we'll be able to see this in a diagram in just a moment. But what would happen do you think if we called b1.constructor? What do you think would happen? What would it point to? Well let me not ask what it would point to, let me ask what should it point to? What should b1.constructor be? We would want b1.constructor to be the bar function, right? If .constructor means was constructed by we would expect for b1.constructor to point to bar. But let's analyze what it actually is. B1, does it have a constructor property on it? No. So let's go to bar prototype. Does bar prototype have a constructor property on it? Not anymore. The default one that was there on line eight did have a constructor property but we threw that guy away and created a new one so that we could link him to Foo prototype. The new bar prototype that we created by object.create doesn't have a constructor property on it. Guess what happens? We then delegate up to Foo prototype. Does Foo prototype have a constructor? And what is Foo prototype's constructor point to? Foo. We get the really bizarre behavior that b1.constructor is Foo. That's weird. b1.constructor ought to be bar, right? How could it possibly be Foo? Foo didn't construct him. The problem is the .constructor doesn't mean was constructed by like you think it does. It's just an arbitrary property that happens to exist or doesn't exist. There is one way of solving that and that is on line 13 you can add a constructor to the bar prototype and point it manually at bar. But you can't just do bar.construct, bar.prototype.constructor equals bar the way it would seem like because now you've created an innumerable property and that's going to break your foreign loops. You actually have to use object.define property and create a non-innumerable property with a value. Sucks, right? This is the kind of crap that we have to deal with when we start trying to force the JavaScript mechanism to pretend like it is something that it is not. It's just one of the many things that are syntactic problems and it's one of the many reasons why for two decades now nobody writes this code anymore. They just use the user libraries to fix all of these problems. My thesis to you is what if there was a way to get rid of having to use all the libraries? What if there was a way to do this stuff without all of this complexity? And that's what I'm driving towards, a different way of doing it, okay? Questions so far? All right, there is the linkage and I want you to pay attention to that linkage as we go throughout the next several slides. B1 is prototype linked bracket bracket p linked to bar prototype which is bracket bracket p linked to foo prototype. That's the linkage. Those are the only objects we actually care about.
Linked Prototype Diagram
Here's that diagram, the one that I have up in the board in a much more complete fashion and showing you both the bar and the foo in play. We have an object. Let me use my laser pointer if you want to try to show up on the screen. I don't have line numbers to use so you just have to hear me. We have this square that's next to the foo that's foo prototype and it has a constructor back. And then we have a square that's next to the bar that's a prototype. But you notice the dotted line shows us the implied relationship because this guy didn't have a constructor on it so his implied relationship is that the constructor is foo. Same thing down here with b1 and b2 they have an implied relationship that their constructor is foo which is just nonsense. But we see the consistency that those bracket bracket p relationships link exactly where exactly we expect them to link, okay? Now unfortunately, this is kind of a fib because this isn't all that's going on in that previous code. I actually have to show you an even more complex diagram to let you see what's really happening with that previous set of code. You should note that some of this stuff will look familiar, we already see the foo and the bar. Those are still here. But now all this stuff up here in the top left corner that's all brand new. The whole bunch of more arrows and dotted lines. And your brain is probably going to start to explode at this point if you think about this diagram. This took me more than a day just to create this one diagram. It's complex. Now there are two takeaways to get here. The first takeaway is this is really complex and if you feel like that you want to deal with these mechanisms with all of this then you better print this diagram out and stick it on your monitor next to those other posted notes 'cause you're going to have to deal with this complexity every day of your life. That's one takeaway. There is another takeaway. There is a more optimistic take away from this. That even though there's a lot of complexity here there's actually an amazing amount of internal consistency going on. Because everything that we can observe about the language is explained by the exact same core set of rules that we've already talked about. For example, you remember when we talked about function prototype bind and magically Foo could call Foo bind? You may have wondered, how is that possible? This diagram explains exactly how that's possible because look at bar and Foo, they are functions or objects which means that functions have an internal prototype linkage. So they delegate up to the function .prototype. And that's where they get .call and .apply and .bind and so forth. So all of the mechanisms that you can observe about the language are explainable through these relationships in these arrows which is a nice internal consistency. There's not actually a lot of magic going on. It's all the same thing, but it's complex, it's difficult. And what we come back to is when it comes down to it, all of these circles and arrows are completely irrelevant. What we really only care about are these squares 'cause the squares are where all the action happens. The objects are where all the action happens. All this other stuff is a whole bunch of distraction that we use to get there. So wouldn't it be nice if we could just make the squares without all the other crap? And that's where we're headed. Yes? I'm a little bit confused on this question, but I'll ask it as best I can. Sartav Si is wondering in the previous couple of slides, the example, where you're assigning bar.prototype to object create Foo.prototype, if you were to reassign Foo.prototype later, would bar.prototype inherit it, or would bar.prototype be pointing to your original Foo.prototype? Kind of neither because inherit is the wrong word. Let me see if I can. What Chris W says there is correct. It creates a brand new object that has a prototype linkage to the Foo prototype object. It's not a copy, it's not an inheritance, it's a new object with a linkage. Hopefully that answers it. We'll see more about object create in a little bit. We'll come back to it. All right, so this diagram sucks. But there's hope because there's a way to get a lot of this complexity erased.
Quiz: Prototype Behavior
Firstly, what is a constructor? What's that? Property. Oh, I thought you said problem. I would agree, it is a problem. What is a constructor? It is a function that is called with the new key word in front of it. .constructor is a property, but a constructor, a constructor call, is a function that is the new keyword in front of it, that's it. What is bracket bracket prototype? What is that prototype linkage and where does it come from? Points to the prototype of the constructor used to create the object? Sort of. Bracket bracket prototype is a linkage from one object to another object. Where it comes from, there's two different ways that we've seen. We can get that linkage from object create which just links it to another arbitrary object, or we can get it indirectly as step two of the four steps of the new keyword. But either way we end up with one object linked to another object. Everybody following so far? How does that prototype mechanism, how does it affect how we deal with an object? Similar to a lexical scope where if you go up to the next object-- We can call a property or a method on an object reference, and if they can't handle that object or property, that property or method reference, it delegates up to prototype chain to a different object. Right? It's an amazingly powerful mechanism, this delegation thing that we're getting to, the fact that we can have these sort of, the object almost can be sort of a fall back object. But the fact that we can delegate from one object to another object is a powerful pattern. You notice in all of this I had to discard anything about copying or whatever. We'll come back to copying. How do we find out about where an object's prototype where that prototype linkage points to? There were three ways that we figured it out. We could give an a1 or b1. How do we find out where his prototype linked to? Dunder proto. Dunder proto. Object.getPrototypeOf. And what was that third crappy hacky way? (mumbles) .constructor.prototype. All right. Just as a reminder. I said that this keyword works really nicely, but just as a reminder we still have exactly the same problems with these bindings that we had before when we're only talking about these keywords. If you take a1.speak and you pass it into a click handler all by itself, what's going to happen too is this reference. jQuery is going to force it to be the button rather than our a1 object. So you still have the same problem where you need to deal with .bind, hard bindings or whatever.
Exercise 3
This next exercise, again, probably shouldn't take the ten minutes but what you're going to do is essentially you're going to take the fixed version of what you finished in exercise two. You can either take my fixed.js or you can take yours if you like your code either way. But that's going to be the starting point for ex3.js. So when you open ex3.js you'll see that it's empty and it says copy in the fixed code as your starting point. So I will do that, I will take the fixed version from ex2. Copy that in as my starting point. Now what does read.me tell us to do? We're going to revisit the work from exercise two but we are going to take what we've just learned about the prototype and we're going to do away with the module pattern, and instead we're going to implement this as a class with prototypes. So I'm going to get you started and then I'm going to give you a couple of minutes so that you get some practice with it. So the first thing is that we no longer have a module factory. What we're instead going to have is a constructor which we'll call notes manager for convenience sake. Consistency. We'll come back to his contents here in just a moment, but now these things that were private methods inside of our private functions, inside of our module, these are now going to be public methods on our API. And the way we do that is NotesManager.prototype.addnote equals function that takes a note parameter. And then we un-indent one level. Add a semi-colon. Now in all places inside of these functions that they reference things that were private variables, they need to now reference properties under this object. So I need to say this.notes.prepend. I'll do one more for you. NotesManager.prototype.addcurrentnote equals function. Add my semi-colon. That new note, that needs to have this reference in front of it. This guy needs this reference. This guy needs this reference. And this guy needs this reference. So your exercise is to continue that conversion, convert from the module format to the prototype format and insert these references. Pay particular attention to your event bindings, make sure you're using binding where you need to, and I'll give you five or eight minutes for you to kind of play around with typing all that out, and then we'll regroup.
Exercise 3: Solution
I imagine many of you are probably still doing your copy and pasting of .prototypes and .this references all over the place. We won't spend a lot of time belaboring this because this is mostly just tedium, but I want to point at a couple of things. First of all it was asked, could I do something like NotesManager.prototype equals and do an object literal and just do things like add note and function expressions? And the question was asked, is that possible to avoid some of this typing? The problem that you've done there is you've thrown away the built-in .prototype that was there. And that things that some people want like the .constructor reference, and it might have had a linkage to a different object that you were throwing away. So you want to be careful about sometimes you want to be careful about your .prototypes because sometimes you can end up losing information. This way, generally we do this.prototype stuff all over and over and over again. Yeah? Do you use something like jQuery extend to get around that problem? Most of the class libraries out there do provide some sort of shortcut to this because this is one of the many things that people don't like dealing with. jQuery extend as well as a hundred other utilities that are like it are all about trying to pave over some of these problems. All right, a couple of other things to point out like this show help one. I don't know if anybody got to working on that one. But if you do prototype.showhelp equals function, un-indent, there's a certain special problem that we're going to have to deal with here. All right, so we know inside of here I can do this .help and I can do my document.add event listener. Now this function handler thing that I'm binding to there, I'm going to need to do this reference inside of it, but what's going to happen to this reference if I just pass that function like I'm doing? It's going to be the button in this case, both the DOM API and the jQuery API manually will bind it to the element that fired that. So that's not good. So one solution is to do hard binding to do .bind this on the end of that function so that we force the function reference to be bound to the proper this. That fixes one problem and creates another problem. And the problem that it creates is now, you might now have seen this, but I had a name for this function so that I could unbind it but I can't unbind it by name anymore because the name of the function isn't the actual function that was bound. The function that was bound was that new hard bound function. And we, in fact, don't have a reference to the hard bound function so we have no way to do this remove event list in there properly. Really, this isn't a good solution for doing .bind this. And now typically I would advise against this particular thing but you've probably seen people do stuff like var self equals this. And they can do self here. And then rather than doing this reference we can do a self-reference. Now most of the time I'm going to tell you if you're doing stuff like that you're completely shooting yourself in the foot because you went to all the trouble to do this mechanism style code and then you fell back to lexical style code. The var self equals this is usually a code smell that you're doing something wrong in my opinion. But this is what one tiny exception case with these event handlers where the other way of doing it is just much harder. So it's easier to fall back in this exception case, to a var self equals this. But in general, if you see people doing var self equals this I think that's them not understanding how the mechanisms work. I won't belabor most of these other ones. A lot of these other ones are helpful but let's just point this one out. Down here in our init function, we're definitely going to need to manage all of these references, so I'm going to have this.open_help. I'm going to bind it to this.handleOpenHelp and do a manual bind this. So I have to do that in every one of these which kind of sucks. Does everybody see why I'm doing that? And so on. Now all of these things that were private variables down here we no longer have any private variables so we can get rid of all of those. We no longer have any of this stuff. Assuming we had finished the rest of our conversion then all of this stuff would be just things that were added to that prototype object. And so down here instead of having a notes manager we would say something like var mynotes is equal to new NotesManager. And we'd reference myNotes.loadData and myNotes.init. And lastly because we are keeping track of some state like our notes variable for instance, up in our constructor we're going to want to initialize this.notes is equal to an empty array. Yeah. Which do you like better? The module or the prototype? Unequivocally the module pattern is much more useful in my code than the prototype pattern. But we haven't really seen my favorite pattern yet. We're getting there. Okay, so in addition to all the clunky syntax and all of those things that are falling over, it's just a more complicated mental model to try to pretend that this is classes, and most people solve that problem, as I've said, by using some library to pave over the differences. And any time you have to use some library to pave over the differences you should ask yourself, "Is this too difficult? "Am I doing it the hard way? "Is there a better way?"
Inheritance
So let's talk a little bit about the formalities of what classes imply for us. And let's kind of give some specificity to why JavaScript isn't working the way that we thought it should work. In classical inheritance we have a parent class that we might call Foo. And when we instantiate Foo, and we create an a1 instance of Foo, there is a copy of behavior from the parent class into the child and there's another copy that happens when Foo gets copied into a2. And when we create a child class called bar we're copying the behavior from Foo down to Bar and then another copy into bar's instances. This is not only a physical thing in terms of what the compiler's doing, but this is the most common way that metaphorically we explain how classes worked. If any of you ever took computer science classes or whatever, if you were ever taught, you were probably given the metaphor of the blueprints, the class represents the blueprints for some building and then you have, so you have an architect that lays out the blueprints but you have a builder that comes along and builds your building. Well, the builder is copying the characteristics from the plans into the physical building. Once the physical building is built there's no more relationship to the original plans. It's not like they're linked or tied in some way. It was a copy. So we can go back to biology, we can talk about parents and children. And when my child inherits my DNA they get a copy of my DNA. There's no linkage. When my son breaks his leg I don't break my leg. There's no linkage between the two because everything about inheritance, the word inheritance means copy. So if the mechanism in JavaScript doesn't do copying, that's why I think it's wrong to call it inheritance 'cause we're using a word in the wrong way. Now there are some people that call this prototypal inheritance. There are some people that say JavaScript doesn't have inheritance, what it has is prototypal inheritance. In other words we stick the word prototypal in front of the word inheritance and somehow magically we've divorced ourselves from the fact that inheritance means something very different. To me that's like me holding up an apple in one hand and an orange in the other hand and saying, "No, no, no, that's not an apple, "it's just a red orange." You would look at me and say, "That's ludicrous. "Just 'cause you put the word red in front of it "doesn't make it an orange." Or doesn't make it not an apple. It intrinsically is something based upon its characteristics and what you call it, you can call it what it is or you can call it something else and confuse me, but what you call it doesn't change what it is. So in my opinion inheritance means something and we can't just put the word prototypal in front of it and make it mean something else. And not just something else, something completely opposite is what I'm about to illustrate. So in JavaScript, the way things work, this is called prototypal inheritance, in JavaScript we have an object that's arbitrarily labeled Foo prototype. And when we create the a1 object you notice that the arrow now goes in the opposite direction 'cause it wasn't a copy at all. It was a behavior link. It was a delegation link. So a1 is linked to Foo prototype and a2 is linked to Foo prototype. And bar prototype is linked, and b1 and b2. The arrows go from right to left and bottom to top which is the complete opposite of the previous slide. His mechanisms are fundamentally in their very intrinsic DNA, they are opposite of each other. One of them is copy down, one of them is a delegation up the chain. And what we've been trying to do for 20 years is make a mechanism that works like this, pretend like it's a mechanism from the previous slide. And we've been doing all kinds of things. You've heard of the mixed in pattern which manually copies things from one prototype to another. All manner of different variations on it I could spend hours and hours talking about all the different variations. 100% of that is an attempt to make something that works like this look like it works like the previous slide. So we're doing all of this work and I think it's just hiding the fact that we could look at a mechanism that works like that and see how we could take advantage of that mechanism itself because that mechanism has a lot of power to it. This is another design pattern by the way and that design pattern is called behavior delegation. So rather than saying that JavaScript has inheritance or prototypal inheritance or whatever other silly label you want to put on it, I think it's more appropriate to say that JavaScript has behavior delegation. And that's a design pattern that we can adopt in our code. Remember this code before when we say a1.speak? I've already used this word before but when a1 is able to call speak, you notice the way that the mechanism works, it wasn't because a1 got a copy of speak. The reason a1 was able to call speak is because he was able to delegate up to a different object that had a speak method on it. It's a completely different mechanism than what happens with classes.
OLOO
I showed you the complex way, the way everybody's been trying to do it for 20 years. I'm now going to perform a magic trick. I'm going to take that complicated code and I'm going to simplify it. And I'm going to show you how we can get the same behavior, the exact same functionality without all of that extra croft and confusion. That's a tall order but I'm going to perform this magic trick in the next couple of minutes. And what I'm going towards is I needed to come up with a name for something to contrast with OO, with object-oriented, with class-oriented coding and I came up with this phrase OLOO which stands for objects linked to other objects because in reality that's actually all that we care about in JavaScript. The only thing that we care about is that there's b1 object linked to another object and linked to another object. That's the only thing that matters. The constructors and all the .prototype references and the new keyword, all that other stuff is just distraction to get us at these three objects linked to each other. So, could we just create those objects without the distraction and get the same benefits? And that's what I'm going to do. In fact, what I'm going to do is derive over several slides, how we get to what I call OLOO style code that is Objects Linked to Other Objects only, how do we get to OLOO style code? And the interim steps are going to look a little weird, so you got to just bear with me. You know how magicians, the way they perform their tricks is they distract you over here so that they can perform the trick over here. I'm going to do the reverse. I'm going to tell you what to look for. And what I want you to keep your eye on is that object, that object and that object. Don't get distracted by all the other stuff. Pay only attention to the objects 'cause they're the only things we care about anyway, okay? The first thing I want to do, to simplify this code, is I need to get rid of any kind of reference to a constructor like new bar. That's class-oriented thinking, it's more complex, it's more mentally taxing we got to get rid of it. So this line 17, I'm going to change line 17 to not deal with a new constructor, okay? Ready, here we go. Okay, now line 17 has become two lines which temporarily is going to look worse but you just got to bear with me on these intermediate forms. We now are using a utility called object.create which I already showed you before, I make a b1 object that is linked to the bar prototype object which is what we want, and then I temporarily have to manually call that bar function with b1 as my context. So temporarily, this looks kind of ugly but it'll get better. At least we've gotten rid of the new keyword, we're not doing class instantiation anymore, we're just making objects linked, okay? And now, I remind you that we still have a b1 linked to a bar prototype, linked to a foo prototype. This code does exactly the same thing as the previous code, same capability, okay? Now the next step of my magic trick is I want to get rid of any references to these .prototypes that are here, this.prototype I got to get rid of that reference, all these .prototypes over here, this function constructor. I got to get rid of all that 'cause that's way too confusing, okay? Everybody ready? Now I called it capital B because of consistency sake but it's not a constructor anymore, it's just an object. We have a bar object that we can add methods directly to it, there's no .prototype references or anything, we're just putting properties directly on objects. And look down here, look how much simpler this got 'cause now all they do is say object.create bar. I just linked b1 directly to bar instead of linking it to a .prototype or some constructor or some other confusing things. I just linked b1 directly to bar. So, I used my little utility object create to do my linkages and object.create becomes the hero of the party 'cause he does what we need without all that other confusing crap going on. And we still end up with b1 linked to bar, linked to foo prototype. Is everybody following so far? Final step of the magic trick, okay? I got to get rid of all these references to foo.prototype and function foo constructor I got to get rid of all that. Everybody ready? Bam! Now foo itself is just an object that has methods directly on it. Bar is just an object with methods directly on it. And b1 is just an object that is linked to bar. So, we still have, in the final tally, an object linked to another object, linked to another object. We have all the same capability as three slides ago. The fact that they can delegate to each other, the fact that we can set up multiple delegations and all of that stuff, we have all the same capability but what we have now done is gotten a syntax that has completely removed any relationship to class-oriented thinking. These are just peer objects that delegate to each other. That's all it is. As a quick example, and I talked about this in my book, "This and Object Prototypes" book that I've written, I talk about all this stuff. And as a quick example, you think about a login controller and an authentication controller. Your login controller is a peer object to your authentication controller. It's not one is the parent and one is the child, they're peer objects. One of them handles managing your login form and one of them handles making Ajax calls to the server to find out if the password was correct. They're two peers to each other. And one of them needs to delegate to the other so that the entire task of getting you logged in can complete. So, the login controller delegates to the authentication controller. It's a different way of thinking. Instead of orienting your code with parents and children and overloading and polymorphism and all of that stuff that you've been trained on for 20 years, you think in terms of the simple objects delegating to other objects. Like b1 delegating to bar, delegating to foo. As an example for instance, you could have, foo is a general utility object that a bunch of different objects can delegate to and utility methods like loggers and other things you delegate to the utility object to use it.
OLOO Questions
What if you wanted to delegate like b1, for example, to more than one object? There's only one prototype. Okay. So bar cannot have an init function? Bar doesn't have a constructor. It could have an init. I had on the previous slide a bar had an init. But really, in all truth, if you went back to the original code, this is the only constructor code that mattered anyway. So, in the final analysis I moved the init all the way up to foo. Sorry, lots of arrows here. I moved the init all the way up to foo 'cause that's the only place we ever cared. So, when I say b1.init it delegates all the way up the chain to it. Now the substance of your question may have also been, "Can I do the shadowing thing? "Can I have multiple objects with the same method?" And I would suggest to you, if you choose to do shadowing and you have all the same problems with all that crappy manual explicit polymorphism thing. If you choose behavior delegation, then you would make these objects have unique names for their unique tasks. So, you wouldn't call it find on two different objects because that's general names. You'd call it "find task" and "find user" or something like that. And by virtue of them having different method names they can easily delegate to each other. So there's no more constructors? There's no more constructors. If we need to do initialization task we can have functions that do initialization task. There's another thing by the way, kind of brings up a point, there's another thing by the way that people sometimes point out. They say, "Well you turned one line of code "in the previous thing into two lines of code." I mean despite all the other simplification that I did up here, people still get mad at me that I've forced you to do two lines of code instead of one. My response to that is in the previous code you were required to do both your construction and your initialization in one step. You have no choice 'cause that's what a constructor does. In this piece of code, there are two separate steps and they theoretically can happen at two totally different times. For example, you now have the flexibility to create all of your objects in a pool at the beginning but wait until later to initialize them. And you didn't have that capability with constructor-based coding. So, I actually think it's a benefit that there are two separate steps but they are in fact two separate steps. Yeah? Go ahead, Mark. I was just curious, like the performance characteristics. If you have an object that has all these methods onto it you create lots of those objects versus you use the prototype. Doesn't the prototype perform better because the prototype only has one instance of the method versus an object, potentially upon the instance of-- We don't, that's the point. What's deceptive here, and you just have to take my word for it, this is the exact same mechanism and functionality, it will have the exact same performance characteristics. The only difference is that it's less code to get there. But there's still just one init function on the foo. If I create a b1 through b1000, I don't have a thousand inits, I still just have one because I'm still using delegation. The difference is I have a lot less code and a lot less complexity to get the same result. (mumbles) create a thousand bar (mumbles). In that case, yeah. If I had bar1 through bar1000 as a thousand child classes I'd have a thousand bar prototypes. So, yes, in that case I would but the real question is usually what if I have a thousand instances? Yeah, so if you have a thousand instances of (mumbles) for a thousand different objects you would want their methods to be from another object that it was linked to. That's usually the design pattern. Your methods are delegated to but your end leaf nodes are the ones that hold states. Your b1 through b1000 would have just your meat properties on it. So then you'd only have one instead of its per one method per-- Generally, that's how you would present it. That's cool. So everything that you're currently doing right now or you're doing .prototypes in your constructors or maybe you're using one of these userland libraries, I'm not suggesting that you would lose capability, I'm suggesting that you can think about the design pattern differently and you can have simpler code. We haven't lost anything from the previous slides. Yeah? I have a couple of questions coming in here. Oliver K. asks, "Are there real world examples "of this OLOO style?" OLOO is something I invented recently. So, there aren't a lot of other examples. I'm still out there trying to convince people stop trying to do classes. I got plenty of code that I use OLOO style in but it's still something that 99.999% of the JavaScript community still does things will classes. And what I'm hoping to do is evangelize the concept that there's this other better way of doing things. We got another one. Oscar P. is asking if you can please explain object.create. I probably should do that and check. Yes, I will show you the object.create because every magician has a way that they do the trick. I will show you how to create in just a second. Can you quickly summarize what the main pushback you get when you push this through (mumbles) to the class philosophy. Is there like a common (mumbles) the main contention point. That's a great question. So, I expound amazingly long detail and length in the book and I recommend reading this in object prototypes book chapters 4, 5, and 6 of that book are all about what we've just discussed and I lay out the full case. But the primary pushback that people give me is but classes are how we've been taught to design things. Everybody has this mindset that class design pattern is the only way to properly design software. And what I'm pushing back on and saying class design is an option and here's this other option called delegation. And given the choice between the two, delegation is the one that goes with the flow of how JavaScript actually works and class orientation is the one that goes opposite to the flow and you have to do a lot of work to make it work. So, it's just a different design pattern. But the primary pushback I get from people is, "But no, there are certain problems that require classes," and I say no. There's a really interesting paper I just recently read, I'll try to maybe find it and put the link in the chat but I'm sure I tweeted about it. If you actually go back and you look at the way the real world works this whole concept of classification is actually somewhat unnatural because classifications don't really work. And delegation, this prototype mechanism, is actually a lot more of a natural thing but we've spent all our careers being told that classes are the way to design proper software. So, that's the biggest pushback is people don't want to change their thinking. All right, so we have this b1 bar in foo and I promised you simpler code. Hopefully you can see ostensibly that there's a lot less complexity to what we're managing in the code, but that's not the only story. So, I want to go back to the old and busted form. This was with the b1 and b2s init. This is the old and busted form and remember the old and busted diagram. Here's the new hotness. This is OLOO style code. And here's the big money shot, the payoff, because here's the new mental model that you need to keep in mind. That's it. 'Cause all we care about is the objects and their relationships to each other. We don't care about constructors, we don't care about these indirect creations of things we just directly create the objects and directly create the relationships. That's all we ever cared about anyway. So any good magician doesn't want to tell you how he does his trick. How does object create work? This is the polyfill for object create in pre-ES5. Look at that. We've got functions and prototypes and new constructors. We took all of that crap out of our code and hid it inside of a nice clean utility. I've got some links up here discussing other sort of issues. The second link in particular talks about reflection. If you've ever dealt with reflection on classes and their relationships to each other it compares class-oriented reflection mechanisms in JavaScript to OLOO style reflection. So, you can take a look at some of those.
Quiz: Prototype Unit
How is Javascript's prototype chain not like traditional/classical inheritance? What's the key difference? To copy links. It doesn't copy, it links. The errors go in the opposite direction. What does the behavior delegation mean and how does it describe the object linking in JavaScript? A new object delegates behaviors to its prototype. And any object made from the same constructor shares the same prototype. I like the first thing you said. I don't like the second thing you said that much because you're talking about constructors. But, yes, objects delegate up the chain. So anytime you call a property or method on one object and you can't handle that property or method it delegates up this prototype chain to another object. What the object happens to be is arbitrarily either simple or complex depending on which style of code you like to write but the fact of the matter is that objects delegate to each other. Why is "behavior delegation" as a design pattern, really what I mean is why is this, not OLOO, I mean the delegation. What is the benefit of the delegation in the design pattern? They don't have copies of function. You don't have copies of the functions. So, let me state it this way because it might be a little, it might be a little bit abstract of a question for me to ask at this point in our discussion. So, let me just kind of answer my own question. With delegation, we are embracing the fact that all objects continue to exist and they are dynamically and changing. And that linkage that occurs is a dynamic linkage at runtime. With classes, they're sort of a snapshot copy that occurs. So, once I've made this copy, then if I change the parent class in some way it's not affecting the child. But with JavaScript and really with embracing the delegation design pattern we embrace the idea that foo can change during the runtime and bar automatically now gets to delegate to a changed foo because it's a live link. So it actually is a much more powerful mechanism. As a matter of fact, it's been said and I agree. Delegation is more powerful than class because you can implement classes in delegation but you cannot do the reverse. You can't implement delegation in a class mechanism. What are the tradeoffs to the prototype mechanism? They're never going to add method missing in the JavaScript. They are actually adding it. It's called proxy. (laughs) You can't shadow-- That's one of the downsides to the way the mechanism works in JavaScript is that shadowing is kind of awkward. There's some debatably, depending on your perspective, ES6 actually adds a class keyword and they add a super keyword. And so they're even further going down the bad path that I think we shouldn't be going down but they've tried to syntactically solve some of those issues, not all of them. But you're right, shadowing is still kind of an awkward thing. But one of the downsides to delegation is that whether it's delegation the way I've shown it or whether it's the old class prototype style delegation everything's public, which means you don't get any private state, you lose all the capabilities of encapsulation. So modules are nice because you got encapsulate private state but prototypes lose that. Prototypes are nice because there's only one copy of a method and if you create a whole bunch of instances you've got less memory usage. So there's these tradeoffs that happen between the two. I've been in the industry now like 15 or 16 years and every one of the jobs I've ever had I would see these code bases with these fantastically complex five level deep hierarchies of inheritance, with specialization and all those overloading and all those stuff. And then when it got down to it at the very end the very leaf node they just created once instance of something. I know you laugh at them but it's ridiculous how often that happens that we go to all this trouble to create the classes because that's how we were told to design software, but in reality we don't take any advantage of it at all. We got to create all these hierarchies and then we just instantiate one of them. Well if you're just going to instantiate one of them why didn't you just do a single flat level module? Like create all of that extra complexity of software design? So it was asked in the chat and I'll expound upon it. 95% of the time when I design software I use the module pattern because I'm not creating multiple instances so it's not a big deal that there might be two copies of the methods or something. And the other 5% of the time, when I do choose to use delegation I use OLOO style rather than the constructor prototype style. So if you use the module pattern for 95% of your code, how do you handle managing state with say 100 objects? I very rarely have 100 objects. It's just not that common in the real world JavaScript. We think in theory, Oh yeah, let's instantiate this thing. I'll have a 100 calendar widgets on the page but in reality we never actually have more than just one. I mean, it just comes down to if you really did have a case that you legitimately wanted 100 copies of the thing then use delegation, but it just doesn't happen very often for me in the real world. I work on a lot of interfaces with complex interfaces you might have 50 or-- What would you have 50 of in a complex interface? In the case of the builder that I'm working on now, it's like there's it could be 5, or 6, or 7-- Of what? Of an item which is a blueprint item and then within that item there's lots of like adjoinable edges that each have state. So if you did an actual benchmarking of the performance downside you might say to yourself, Oh it's terrible that I'm copying the method seven times. In reality, you would have to be creating hundreds and hundreds of objects before the optimizations that the engine is already doing, couldn't keep up. So, if you're just doing five or seven of them I still think modules would probably suffice, but-- Yeah, there could be like 50-- I think you would literally have to have like 500 or more before you could convince me you really have to go with the delegation pattern, but that's just me. Honestly, five or seven of them I wouldn't even believe in using modules. Even if one item has 100 methods or 50 methods? Yeah. The JavaScript engine is just so good at optimizing this stuff, it's just not going to really matter in the real world unless you get to a really large scale of number of instances and I just don't see that very often.
Exercise 4
Rather than belaboring some time because we still got async to get into I want to give you as homework Exercise 4. Just real briefly to orient you, it calls for you to create a widget and a button as a parent and child class. So you first use the prototype style and model it as a parent-child class sort of a thing so that you can instantiate buttons on your page like you're instantiating UI widgets. And then it asks you to go back and rethink about it in terms of OLOO style and in terms of delegation. Or rather than having a parent and child you have two peer objects, you have a general widget utility object and you have a more task specific button object. So, that exercise has both the open files for your to work on as well as the fixed version so you end up at the end of that exercise with a nice side by side comparison between class style code and OLOO style code and it lets you further decide which one works for you. There's a question online from James L. Are there any circumstances in which it makes two of your patterns? As in use OLOO to delegate a module or vice versa? Yes, I have done that before. It doesn't happen very often but I have done that before. You have to be a little bit careful because delegation can sometimes be kind of counterproductive to the encapsulation that you're trying to do with modules and vice versa. So, you have to be a little bit careful with it. But I have done delegation between two encapsulated modules before. Is there a generalization you can make about what instances you would do that in? Probably not. (mumbles) Yeah, so you have to start thinking in terms of delegation. Delegation is not a general hammer that you'd use everywhere. I only use it 5% of the time at best. But when I do want to take advantage of the prototype mechanism, I think delegation's a cleaner pattern than classes for it. All right, so without belaboring that stuff, I do encourage you, as your homework, to take a look at Exercise 4, try your hand at it.
Exercise 4 Solution
If you recall at all, Exercise 4 was at the end of our discussion about OLOO when we had compared and contrasted various object design patterns in JavaScript and I had presented you OLOO, Objects Linked to Other Objects, as the pattern of delegation implemented with objects being linked through the prototype mechanism. And I assigned this exercise because I wanted you to have yet another side by side comparison of the traditional/classical prototype style coding in JavaScript compared with this new style that I'm calling OLOO. So the task, the exercise calls for you to finish out the definition of a widget parent class and a button child class and then show how you can instantiate those buttons to have them on the screen. So, I will show you what we start out with. This is the empty file. By the way just as a reminder both with the exercises from yesterday as well as the exercises for today, I recommend that you have a separate copy of that folder so that when you make changes to those files you can go back at some point later and have pristine copies. Yeah? The question earlier today. Jerry K. is wondering if Chrome 34 will be good enough for the exercises on a Mac since it's not available on Linux. Yeah, Chrome 34 is fine. We just don't want somebody on Chrome 28 or some old version, but Chrome 34 is fine. Okay, so the way we would start out, the first part of this task is to do this using the traditional class design approach. This is a parent class and a child class. Class orientation tells us that we should have a render method on our parent class that sort of an abstract or base generic render. And then of course on our button class we're going to override the render and add additional behavior to it. So, let's start by first declaring or defining our button constructor. So, I will uncomment this code. This will be our button constructor, our button class definition. And you're going to need, if you read in the ReadMe, you're going to need three parameters that you instantiate a button with. First is a width, a height and a label. Label obviously being the visible text that you're going to have on your button. So, we know that the widget parent constructor already handles the width and the height that it even goes ahead and sets up an element property to hold our actual DOM element for us. So, really all we need to do is call that parent, that parent constructor. Now unfortunately with JavaScript in its current version, we don't have a way to express this with a super method. So, using sort of a manual polymorphic type of call we can say the widget function, we want to make sure that we pass in the this.binding that is our current one and then pass along the width and the height to our parent constructor. Next, since the parent constructor doesn't know anything about a label we need to save off our label. So we can say this.label is equal to the label parameter that was passed in. And finally, I've shown you here how you construct a button element. This hasn't been added to the DOM yet because the parent class is going to do that with the append to function. But we need to create our button elements so that it can be added to the DOM. Next, we need to start adding our methods to our public API of our class. So, the way we do that in the classical approach is buttoned up prototype. And in this case, we're going to add in render. I can type today. Render will be a function that accepts a parameter that tells it where to render it to. In this case, we're probably going to use the body. We need to call the parent render. So again, in a similar way to calling the widget parent constructor we need to do something similar so we're going to have to do it manually. Widget.prototype.render. And then we need to make sure to override the this.binding so this.binding and pass along that way or function so it knows where to append it to. And then we need to add in our click handler. Sorry, this.elem we're going to bind the click handler for our button to call our button.onclick which we haven't defined yet but we will in a moment and so we will call that this.onclick, but if we pass along like that we know it's going to lose our the this.binding so we need to do a hard binding here to make sure that it will have to proper this context. Next, to define that we're going to add this also to the prototype to function event. Now we want to console log out and I think it specifies in the ReadMe what you should say button and then its name and then clicked. So we're going to console log out the statement button and we can say this.label, the reason that this will work is because we made sure that this onclick is always called with our proper context. So button out put it probably in quotes just to be most clear and then we say that it was clicked. Now we've defined out parent and our child classes using the classical approach. We come down here we want to instantiate it. It's probably what you're expecting. You would say new button. I'm going to give it 100 width, 50 height and I'll say Hello as my first label. My second button that I will add to the page, I'll say Button and I will make it twice as big, actually four times as big, twice as wide, twice as high. Now if we were to save off this code, which I won't save my file since I'm not making local modifications here, but if we were to do that or to open up the fixed version of this code to see what it should actually look like, oops, I didn't get to the right spot, did I? All right, let's see here. Day one Exercise 4. If I open up the fix.HTML, you note there that of course I have my Hello World buttons that have been added to my page. And you also note if you watch the console that when I click the Hello button it indeed indicates which button has been clicked. Any questions about how we did the classical approach to the widget button parent class coding? I needed some semi colons, I guess. All right, so what we want to now do is starting with this as kind of our starting point, how would we then approach this instead of in a classical style, how might we approach this in the OLOO style? And to save some time so we don't get too bogged down this morning, I'm just going to show you the fixed better file, I'm going to show you how it's OLOO and talk you through the different design perspective that I have here. Rather than thinking about it as a parent and a child where the child extends the parent and redefine certain base methods and overrides them with polymorphism and rather than thinking about that as our design pattern, instead we could think about widget as sort of a utility object that every widget on the page has certain common tasks that they would like to delegate to that widget utility object for it to handle. So, we would have a button object that obviously is going to handle creating button widgets and we would have the button widget configured to delegate to the widget utility object. And delegation of course, as we've talked about yesterday, it's a different mechanism because there isn't a copying going on it's a different mechanism to cluster widget code. So here's how I might approach that. I would first start with making widget an object rather than as a constructor function. So here, I take advantage to the object literal syntax for short handing. And I declare that I'm going to have an init function here on line two. That's sort of taking the place of the initialization code that a constructor used to do. You don't have to think about it as a constructor anymore because now we have the power to construct objects separately from when we initialize them. But this is an initialize that we can delegate because all widgets need to be able to do this, this base amount of delegation, I mean this base amount of initialization. We would say all of our UI widgets have at least a width and a height and have at least an element referenced to the DOM object. Now here's where things start to be a little bit different because rather than trying to come up with a generic name like render which I would intentionally shadow and try to overwrite and then cause myself polymorphic headaches, instead I came up with different names for trying to represent more specifically what the different tasks are doing. So, my generic utility on my widget class, I called insert because really all he's doing he is setting up some CSS so we might have been able to come up with a name that sort of stylize an insert or something like that. But its main job is to call the append to function and add it to the DOM. So, he's inserting our element into the page. And so I came up with insert you could've called add to page or insert, you could've called it whatever you want. But rather than using that generic name render that's going to cause polymorphic shadowing headaches I came up with a more specific name. Now moving on to the button object which again it's not going to be a child class, it's going to be a peer that will be able to delegate to the widget utility object. We have button equals object.create widget. We saw that yesterday. That's just the simple way of creating one object that's linked for delegation to another object. And rather than having to add anything with prototypes I can add methods directly to my button object. I can say button.setup, button.build and so forth. So, my setup function is going to call the delegated initialization function that all widgets have the ability to delegate to. But you'll notice that now I can take advantage of delegation because the names are different. I can just say this.init. I don't have to say something like widget.init call this or any of that awkwardness. I can just save this.init and it will properly delegate out to the utility object. I call my this.label, my this.element the same as I did before. Now I also need a build function and the build function is going to, in addition to calling the delegated insert call, it's also going to attach our click handler. This.elem.click and attaching it to our bind function. Finally, my button.click looks exactly the same as before with this.label. The only now difference is we're going to have slightly a little bit more code but more flexibility as well down here because now we're going to have one step where we create a button, btn1 will delegate to the button object. So, we have btn1 that's delegating to it but now we also need to set up our btn1. So, here I'm giving it some parameters like 125-30, 150-40 that sort of thing. And then we call it build rather than render to add those things to our page. So, the key takeaways here are that there's a lot less code complexity in terms of not needing to manage constructors, prototype references, doing those manual polymorphic calls, things like that. We just have objects that are linked to other objects. And you note that we have button1 and button2, we could have a thousands buttons that we're all delegating to the same singular button object so we're not limited in terms of anything that we wouldn't have had before. We're still creating in that sense instances but these are instances that delegate rather than instances that receive a copy of their parent class or something like that. So, we're not limited in any way in terms of our performance or something like that. We just have the flexibility now to deal only with objects, the simplicity that only deal with objects. And we have the flexibility to construct separately from initialization. Yes. It's a question online. If there's some kind of equivalent to super.method or super.apply arguments like, in this pattern where you're basically having a button I don't want to say subclass but I think that's the thinking of the question. So delegate or R delegate E or delegate is the right way to say it in behavior delegation terms. But to answer the question, the question is what if I really wanted to insert the shadowing, what if I really wanted to use the word render as the method name on both of these objects, what if that was really the appropriate thing, what would I do? Well, really your only option in that case if you had button.init and a delegate.init, obviously this.init isn't going to work so you're going to have to do it manually. You're going to have to do the widget.init.call and make sure that you override to the this.binding. That's really the only practical option. JavaScript as of ES5 and below does not have a super method. As of ES6, they've added a whole syntax called with the class keyword, a whole set of syntax to try to even further the pretending that JavaScript has classes. And if you chose to use the class syntax in JavaScript as of ES6, one of the few things that they've done to help the syntax is they gave you a super keyword. But that requires you then to opt in fully into the class design mechanism, it requires you to set aside any of the questions that you may have. I've written a bunch about this in that second title, the first appendix of that book, I deal directly with the class syntax of ES6 and I point out why there are some things that they've certainly made better but there's a whole bunch of things, things that we already talked about yesterday, that they really didn't make much better. So, it's kind of a choice. If you want to keep going with classes you can choose something like super. But outside of classes, there won't be a super mechanism. You'll either have to choose the explicit polymorphism like here or choose to use different names. Now I would make the advocation one final time that picking different names is better proper design because more descriptive names, rather than using a generic name like render which could mean a hundred different things at different levels, being able to choose a specific name I actually think makes software design better. So, you just have to set aside that idea that you've been told that you need to create general and specific overridings with class designs. But hopefully that answers the question about super. Yeah? Could you set up widget and button in kind of the module pattern so that you could create private members as well? Sure. So, to indulge that question for just a moment. If I were to have something like widget is equal to an EFE, and I were to have this stuff on a public API that I returned out. So now widget's a module, right? That's all I had to do to turn into a module and now it's a module that has these two members on it and you might ask, "Well, what if I wanted to have "some kind of internal tracking?" It doesn't make a lot of sense to have internal data on the widget utility because it's really just a utility. But if we did the same thing with button, if we instead had a bar button equals and we did an EFU with the module pattern and we cut that guy out and all these cases if these were, if these were methods on our public API and we returned our public API. So now we've got two modules. You can see how quickly that is to change between the styles when you understand the syntax. And now we've got two modules. And you might ask, "What about these methods?" I mean, "These members here like the width and the height?" So, it would be maybe nice if I could have a private width and a private height and a private label variable, rather than adding those things to some public thing like this, wouldn't it be nice if I could make references to these things. I also need an elem. All right, so if we go down that path and we started dealing with this closure pattern here, I mean this module pattern with the closure, so that we can track these things privately. There's a benefit now because we have the encapsulation, we're hiding details, there's all of that nicety. But I think you're going to start to see why these two mechanisms are sort of orthogonal. It's not very common that you mix modules and delegation. Because what happens with this this.init call? What we're hoping to do is delegate to an init method on some other module and have that guy start dealing with our things. So theoretically, we would like it to be able to do something like setting our private members. But he's an entirely different module and an entirely different closure and he has no access to those properties. So, the usefulness of being able to delegate to a general initializer is completely lost because we hid it. So, we would have to define our entire set of behaviors manually. We'd have to manually call width equals width and height equals height and so forth. So it's not that there's no call for delegation with modules but when you start talking about, "I want to use a module because I want the privacy "of my variables." That significantly cuts off your ability to use delegation. So, they are sort of orthogonal patterns. Could you say your public API equal to object.create widget? And then you would (mumbles) the option to have private members if you want it as well. Yeah, if what you're asking is rather than just making this an object, could I make, and I have done this before, although there's only a few limited times. Could I make my public API delegate out to widget? Well, that's essentially what we would've done, I just hadn't gone that far. But if we did that then and we said, "Rather than calling these things private "we were basically saying public API.width," because that's the only way we could delegate up to a this.init. Rather than these being private variables they'd have to be variables on our public API 'cause that's the only object that the two would share. And now all of a sudden we've gone exactly back to what we were doing before where these are public properties rather than private. So, you could theoretically use this pattern. I kind of call this Frankenstein. But you could theoretically use this pattern to track some things private and other things public. But what you're inexorably going to come to the conclusion is if I want to delegate it has to be public. So, you do get limitations where I want to keep this thing private but I also want to delegate, you can't do that. So, it's kind of this choice. That's why I said that they're orthogonal. But you absolutely can do this. There had been a couple of times when I've done that. Those are great questions. Any other questions about the comparison between class orientation and OLOO? What's the reason behind on line-- They'll need to go back to the-- Let me reset myself just a moment. Okay, the question was what? On line 29 when you have the this.onclick, what's the reasoning behind separating that out into its own method there? Like when you have the this.onclick.bind instead of like an anonymous function there or-- Oh you're asking why wouldn't I just put an anonymous function? Right. Even if I did an anonymous function I'd still have the this.binding issue. So, I could do an anonymous function here that did the console.log in it. But the this.binding would still need to be overridden. So I'd still have to do the .bind this on my anonymous function. And that's a little bit of an awkward pattern to do binds on anonymous, whether anonymous or not but it's a little bit of a weird pattern to do binds on function expressions and line function expressions. You can, but it's not very common for people to approach it that way. So, the question that you're asking is why would I have my own separate handler? Well, proper software design says separation of concerns. Methods should do one task. So my onclick handler is its own method separate from the builder that did the attaching. But you could do it with an in line function, it wouldn't solve any of the problem that you still have to do your bindings. Does that make sense? Yeah? There's a question. Would a strict mode would have an effect on any of these patterns? I think in particular this one is the question but I'm not positive. The only things that strict mode would change is what happens with the default bindings which we're not relying upon the default binding in any of these cases. We're using, at worse, the implicit binding because everywhere that we make a reference to a method we always reference it by object name.method which uses the implicit binding. Strict mode changes how the default binding role is but it doesn't change any of the other roles. So, a strict mode should not change anything about how you'd use OLOO.
Async Patterns
Callbacks
Our final discussion that we'll push through and we'll try to get done as quickly as possible. There's another exercise at the end of this, it might also end up having to be homework because I don't know if we'll have time for it. But we're going to talk through Async Patterns and I'll do my best to move quickly through it. But I felt like it was really important. We spent a lot of time in the weeds down in the deep, you know, trenches of the mechanisms of JavaScript. Felt like it was important to have at least some discussion at higher level abstraction of how we do things productively in JavaScript. Asynchronicity is a reality of our code in JavaScript and so I think it's important for us to talk about what are the patterns that we use to deal with asynchronicity in real world JavaScript. The first pattern that everybody knows about is nesting of callbacks so we're going to talk about what that means, why we do it and why there's a problem. Then we're going to talk about generators and co-routines which are a new, brand new thing that you know, might kind of stretch your mind a little bit because it's a whole concept that JavaScript's never had before. And we'll end our time talking a little bit about Promises. So first I need to set up why are we even talking about asynchronous code and the most basic way that I can explain this is our brains work synchronously. If I describe to you a task like with a set time out of like, if we look at this code here. This is callback base code. If I were to describe as a developer, if I were to try to describe how does this code work? Here's how I would describe it. I'm going to set up a timeout for a thousand milliseconds from now and then when that timeout fires I'm going to print out the string callback. Just in the very way that I described that using English grammar, I described it in a synchronous fashion. Because I said I'm going to do something and then I'm going to wait a thousand milliseconds and then I'm going to do something else. It's subtle but did you see how I just glossed over the fact that there's no way to actually wait a thousand milliseconds? Because I'm not blocking anything and the reality of JavaScript code, if I were to try to describe this, how JavaScript is actually going to handle it here's what I'd say. I'm going to set myself up a timer for a thousand milliseconds from now and then I'm going to come over here, I'm going to process some other work and I've got some other events handling. And oh, somebody clicked a button in AJAX. Oh, it's been a thousand milliseconds, time to go print out this callback. That's how I'd actually describe the way this code works if I were talking about it in an asynchronous fashion. The problem is that our brains don't work asynchronously. We like to think that we're multi-taskers but multitasking is just fast context switching. We're still synchronous thinkers. That's the way psychologically our brains work. All of the biological functions in fact that you talk about that happen, like my breathing and stuff like that, they happen at a subconscious level. They're not consciously happening asynchronously. When we talk about asynchronous flow control patterns in our code, what we're really talking about is how do I take something that is fundamentally asynchronous like a timer. And express it in such a fashion that I can reason about that asynchronous code in a synchronous fashion? So everybody see that? Callbacks are one such way that we do that and a callback is really if you wanted to extrapolate or to generalize what a callback is, a callback is a continuation. What we've said is my entire program up until this point of line one, the entire program that's happened thus far is the first half of my program. And the next half of my program happens inside of this function. So I'm going to split my program in two and I'm going to say I want you to continue my program at some point a thousand milliseconds from now. It's a continuation is what it's called. The problem with callbacks is that they work okay in that one split. They really start to suck when there's more than one split. And almost all real world code there's more than one step to our asynchronicity. And you've probably heard the phrase callback hell. Anybody heard that before? Anybody seen code? This is sometimes called the pyramid of doom because it's shaped, you know, like we see this nesting and this indentation. Unfortunately, callback hell really actually has nothing to do with indentation. So if you've heard that callback hell is about all these nested functions and these indents, unfortunately you've been somewhat misled. So let me try to shed some light on this because callback hell is a real thing and it's an important thing that we need to solve. It has nothing to do with indentation. Here's my proof. This particular piece of code is quite clearly a bunch of nested functions and everybody would agree it's kind of ugly. This code does the exact same thing as the previous slide but you'll note that there's not really very much indentation and there doesn't even really appear to be a lot of visible nesting going on. And what I would suggest to you is that this particular code, I chose a different style. This is called continuation passing style. I chose a different style of code but this code is every bit as susceptible to what the problems of callback hell are as the previous slide. So callback hell must be something deeper than just the indentation and the nesting and what is that? Let me suggest to you a few things that are a problem. We can go back to the set timeout function a few slides ago and I could suggest to you, what if the set timeout function was not a utility that was built into the language that we could trust? What if it was some third party library? Remember what I said is that a callback is a continuation. We take the entire rest of our program if you will and we wrap it in a function and we say I want for you to execute the rest of my program at some later time. So when we're calling something trusted like a set timeout not such a big deal but when we're calling something that we don't trust, like a third party library that we can't even audit and we can't see and we just get a minified copy that we, you know, pull in from their CDN, then we actually have an amazing amount of trust that we've given. Because we have done what is called inversion of control. We used to be in control of the completion of our program up into that line. As soon as we take the continuation of our program and wrap it in a function and hand that off to some other utility we have lost control of our program. We've handed over that control to some other party, in this case a third party API. So, what have we done? There's an implicit trust that's been created when we hand control, when we invert control and handed over to somebody else, what have we done? We have said I trust that you will call my callback not too early, not too late, not too few times, not too many times. If there's important context like passing along parameters, I trust that you'll pass along what you're supposed to and I trust that if anything happens that I need some output, you'll make sure to pass the output back to me, and a whole other litany of list that we trust. As soon as we take the rest of our program and put it in a callback continuation and hand it off to somebody else. There's this implicit level of trust and it's actually a gigantic amount of trust that we're trusting. Now let me give you a sort of a, kind of a tongue and cheek example of this. Let's imagine that you hand a callback off to some third party API. It's one of these APIs that does like, you know, social metrics test, stats tracking and stuff like that. It's tracking clicks or whatever. You need to call this function on their API but it's asynchronously completing so you pass it a callback and you say call my callback when you're done. And there's some bug in their code and instead of calling your callback once they call that callback a thousand times. No big deal, right? Except what happens if that callback charges a customer's credit card because you're on a checkout screen of an e-commerce site? Now all of a sudden you've handed over control of your program to them and you've allowed them to charge your customer a thousand times. Again, it's tongue and cheek but the point of the matter is that there is this inversion of control trust issue when we deal with continuations using callbacks. We are giving control over to someone else. And all the rest of what we're going to discuss for the next few minutes is about trying to solve inversion of control in a different way than with callbacks, okay.
Solving Callback Problems
So I'm going to give you a couple of real quick things that callbacks try to do. These are things that people have tried to do to solve some of the issues with callbacks. For example, here we have the separate callbacks approach where I pass in a success handler and an error handler, and I expect that one or the other is called. But this is even more implicit trust because I'm trusting that you're only going to call one and not the other. What happens if they call the success and the failure? What happens if they call the failure first and then later they call the success or vice versa? How are we supposed to handle that kind of thing? We're trusting that they're not going to but how would we handle that if they did? What would your program do if both callbacks got called? It would probably break. Okay. So this doesn't really solve inversion of control, it just makes it worst. Then we have, this is commonly called node style but I think that's a really bad name. We should called it error-first style code which is that we pass in a single callback but we get an error function. This error parameter is the first parameter there on line nine. The error parameter will be filled with something truthy if there was an error condition and it will be empty if there wasn't. We find ourselves inside of our functions and this happens a lot in node. We do this if else all over the place. Now we don't have two separate functions but we still have one function, and let me ask you the question. What happens if they pass back both an error object and a success value, how would your code react? You'd probably completely ignore the success value because you'd be checking only for the error object. Again, we really haven't done anything to actually solve the implicit trust issues that have been created by callbacks as a continuation style. Okay, here's my little running example that I'm going to give you calculating the meaning of life and here I'm doing so with nested callbacks, okay? The first callback is I'm calling on line five. This getData function by the way, he just waits a thousand seconds and then gives you your data right back. I'm saying a thousand milliseconds from now I want you to pass me 10 back. I'll add 10 to one and my x will now be 11. Then a thousand milliseconds from now I want you to hand me 30 back and I'll add 30 plus one so I'll have 31. A thousands milliseconds from now I want you to hand me back the string that says meaning of life is equal to the addition of 11 and 31. And you hand me back the answer and I print that out which is the meaning of life is 42, okay? It's these asynchronous steps that I'm doing that might have been AJAX calls or click handlers or any other form of stuff. And it should be evident in this code that if we did not trust that getData function we would have had a massive inversion of control trust issue. There's also lots of problems that we have no error handling here. What happens if halfway through it fails to send us back the value where the program just hangs, you don't have any way of doing it. So you have to construct all kinds of elaborate solutions to these problems that callbacks introduce.
Generators
So how could we do something completely different? How could we solve this problem a completely different way? Again remember, the problem, the solution that we're driving towards is to attempt to express asynchronous-looking code in a synchronous-looking fashion, okay? And I'm going to introduce to you this concept called Generators. It's coming as of ES6. So it's this brand new thing that's been invented. It breaks an assumption that you have had about your JavaScript code from the beginning of time. There's something brand new, a whole new invariant that is broken that we've never known before. You may not have even known that you could assume this but it is true that we assume as soon as a function starts executing the first line of its code, we assume that it will finish all of those lines of code before any other piece of code runs. That's called the run-to-completion invariant of JavaScript. We assume that it can never be interrupted and you know, paused and come back. That's true of all normal functions, it's not true of generators. We now have a new type of function that can literally pause itself right in the middle of the function and could be resumed later and that's what are called generators. This is going to bend your brain a little bit but just stick with me. We have this new syntax for function declarations which is function star. Those of you that have by the way, that have dealt with function star you know that's supposed to be function pointers. It should drive you nuts that they chose function star for the syntax but that's what they chose. This is our generator syntax. And it looks like a normal function except it has this new keyword in it called yield that we see there on line three. Now, what is a generator going to do? You see on line seven I execute the function or at least it looks like I execute the function when I call it. But I actually haven't executed anything about the function when I call it, and that's what's different about generators. When you call a generator function, it actually constructs an iterator for you. So what I get back is an iterator. You guys probably know what iterators are. You can call next on them to step through a data set or something. This constructs an iterator to control the operation of our generator. So when I call on line seven, when I call gen I actually haven't executed any of this code yet. On line eight when I call it.next I start up the generator on line two and I run until it comes to the next yield statement and then it pauses itself right there in the middle of the function. And it returns control back to this part of the program. At some later time like the next statement or five years from now, I can call it.next again and it will resume from where it paused and it will run either to the end or to the next yield statement. So a generator can pause itself and then an iterator can resume it. And it can pause itself and an iterator can resume it. It can start and stop an infinite number of times. It's a function that doesn't even have to ever complete actually and that's a new weird thing that we've never seen before. This is a new capability and you might ask yourself, why on earth is, this just seems crazy. How on earth could this actually help? We'll get there I promise. Because I'm going to skip over the co-routine, that's just a little bit of extra complexity that we don't need. But if I wanted to run my generator, What I'm doing here is on the first statement I'm going to say one plus and I'm going to say yield null. Now, when I yield null I'm actually taking the null value and I'm yielding it out. So yield is actually a message passing mechanism. It's actually a two-way message passing mechanism. We can pass messages into our generator and receive messages back from our generator. It's kind of crazy. So, what's actually going to happen with this code is when I run the run function right here, it's going to start up my code and it's going to come to this first yield and it's going to give me out a null value. So that null value will be the return value of that first run call. At some later time I can then say run 10 and when I say 10, the value 10 is passed in as the expression result of the yield expression. So 10 plus one will then be assigned x and x will be 11. It will keep going and I'll say var, y equals one plus, oh, I see another yield, I better pause. So to yield out another null. That null will come back as the return value of this function call. At some later time we then can say run 30 which is going to pass in 30 as the return result of that expression. 30 plus one is equal to 31. We now have x plus y, 11 plus 31 is 42. We yield the 42 value out as the return result of this function call. So it's a two-way message passing mechanism. I know it still looks confusing, trust me, I'll show you in just a moment why this helps with asynchronicity. This is not asynchronous, right? This looks more of-- I'm about to show you the asynchronicity. That was all synchronous but now I'm about to show you the asynchronicity. Now we're going to introduce the idea that my steps don't synchronously iterate. Right here when I say var x equals one plus, I'm going to yield out but I'm going to call a function which is not going to immediately iterate. It's going to wait a thousand milliseconds before it iterates. Look at this code. Does this code look synchronous to you? It looks very synchronous. You could write a test suite like this. Here's my test one and test two and assert this and assert that. But actually underneath the covers this code will start and stop asynchronously. And that's the true power of generator solving asynchronous flow control because it gives us a perfectly synchronous-looking syntax but it allows us to hide the asynchronicity behind the scenes. Okay. A generator can iterate synchronously but it can also iterate asynchronously and that's the power of this mechanism. Generators are a whole brand new thing. There's all kinds of complexity that we haven't even begun to scratch the surface on. I would venture a guess that I'm going to be back here in three or four years and I'm going to be teaching you a new class and I'm going to be talking about generators, and everybody's going to be like, "Oh, of course generators. "Why would we ever have done promises or callbacks?" But it's too new right now. We're still scratching the surface on what generators are going to be like. In fact, there's a new thing that they're even thinking about already for ES7 which is an abstraction on top of generators. There's all kinds of exploration going. I'm giving you a glimpse into what the future of asynchronous JavaScript programming is going to start to look like. You can see how this is drastically different than the way we deal with callbacks and nested inversion of control. Yeah? Do you see a problem with promises and these new generators where they may intermingle when used in the future? The future is that promises and generators are going to work together. Got you. Okay. Yeah. So right now we're not using promises here but the future is that we'll yield out a promise and it will come back when it finishes. And that's already something that, we'll see that in just a moment. That's already something you can do but that's the, I think that's the most likely path to the future, is where the two work together and those will be called async functions by the way. So that's coming in ES7 probably.
Promises
Now let's talk about promises, okay? I know we're running late. If you have to leave, it's okay, I understand. I'm trying to get through it quickly but this is the stuff I'm actually most excited about so I hope this is interesting to you. Promises. Promises, there's a lot of different ways that people explain them. There's a bunch of whole, there's a whole bunch of great blog posts about promises. I encourage you to kind of take a look at some of those. Let me just give you two metaphors for what a promise is all about. Okay, the first one is you walk up to the counter at Burger King or McDonald's or something like that and you're hungry for a Big Mac or a burger, whatever. You have hand the cashier, you order your food, you hand the cashier some money. What usually happens is you don't have your food back right away. What does the cashier hand you instead of your food? Receipts. A receipt and that receipt has an order number on it. So you step back among the other masses of people that are impatiently waiting for their high caloric intake food, and you wait patiently, impatiently for somebody to call out that order number, that magic number on your receipt. And then what do you do once they call out your order number? You walk back up to the counter and you exchange your receipt for the food that you actually wanted. What we have here is we have a transaction that was asynchronously completing. I started the transaction by giving you some money but you couldn't complete the transaction and give me my food yet. You had to give me a promise for some food. You had to give me an IOU for some food and you had to come back at a later time and exchange my order number for my food, okay? That metaphorically is exactly what promises are. I call to a function and I want some end result to happen and that function tells me, sorry I can't finish it yet but I'll hand you back a promise, I'll hand you back a receipt with an order number on it, and at some later time when I get finished with that task I'll let you exchange the order number for the value that you asked for. Does that make sense? All right. The other metaphor that I would give you for promises is what if we could call a function and we weren't sure when that function was going to finish but what if we could subscribe to an event. After calling the function, we have some mechanism by which we could subscribe to an event that lets us know when that function finishes. We might call that a completion event or a continuation event. Kind of like we listen for click events on buttons but this is an event for a function call. That's essentially what promises are. We're calling a function, it doesn't finish yet but it allows us to subscribe to a continuation event. And when we get notified of that event then we proceed. Does that make sense at all? Let's see what that looks like in code. I'm going to use, this is very heretical in the broader standards community because everybody seems to, in the standards community they seem to universally hate the jQuery implementation of promises. Because jQuery had the gall to implement promises in a non-standard way. And jQuery can't go back and change it now because there's 10 million lines of code relying upon it. So, if you talked to anybody in the promises in the standards community and you mention jQuery promises, they will scowl at you and say, "Oh, you shouldn't be using those." I think that's a hogwash, it's nonsense. jQuery has promises, they're useful. It's a pattern rather than an API as far as I'm concerned. I'm going to show you first how jQuery does it. We create these things called deferreds and we pull a promise object off of our deferred. Then we have two separate pieces of code, lines four through six and lines eight through 10 would likely happen in totally different places in our code. Because it's a separation of concerns. Lines four through six are what happens when we want to listen for the event. In this case we want to listen for the done event, the continuation event. So we would return back a promise from some utility and that calling place would be able to listen for the event that was finishing. And then somewhere inside of our code we would, at some later point we would resolve that promise, we would exchange the order number for a Big Mac. When we call resolve on the deferred he will automatically fire the done event for any promises that are listening to him, okay? Here's how we use it for example, creating ourselves a little delay function that I call waitForN. I create my deferred, I return my promise, I set up a timeout for calling d.resolve. That's the typical pattern and you'll see that with all promise implementation, that same kind of pattern, okay? Here's how we use it. We call waitForN a thousand, WaitForN a thousand returns us back a promise so when we call .then, we're listening for the continuation event on that returned promise. Our code says waitForN, wait for a thousand milliseconds then do this stuff. Inside of this function we call waitForN again which generates a whole new promise and when we return a new promise from it, it chains the promises together. This code you can look at it very synchronously. It says wait for a thousand then do this, then do this, then do this, then do this even though it starts and stops asynchronously. You can see that promises give us something similar to what we saw with generators that give us a very synchronous-looking syntax for an asynchronously completing series of tasks. Does everybody follow that? And here's why it's important. Remember when we talked about inversion of control? When I pass a callback into some utility, that utility has control over when my code happens. We've reinverted the control, we've uninverted the control now. We call some utility and rather than giving them our continuation, that utility hands us a promise back and we get to decide what we do with that promise. We listen for the completion of that promise and we decide what to do next. So we've uninverted that inversion of control and brought it back so that we are now in control of the entire completion of our program. Does that make sense? That's why promises are such a powerful solution to callback hell and inversion of control is because they uninvert that inversion of control. Now, promises are actually built in as of ES6 so you can use them natively directly in the language. We're going to get the capital P Promise, so it's built-in, it's already there in Chrome and node, you can play with it if you want. If we construct our promise this should look very similar to what we're doing with jQuery. We construct a promise that we return back and then we call to resolve at some later point. And we call .then and .then and when we return new promises it does exactly the same thing. This is why I don't care that jQuery's API is slightly non-standard because the concept is the same. We still reason about the code in exactly the same way. Kyle, is there part of that chain strategy for each one if you say if I get a timeout and this one I want to do this? Is there like a then otherwise? Yeah, so in native promises, if you pass two functions in, the second function is the error handler for that stage. So there is a way to call reject if you want to fail a promise. There is always an error pack. All right, so we get data. A thousand milliseconds from now it passes along this message, promises have message passing obviously. A thousand milliseconds from now num one will be 10. A thousand milliseconds from now num two will be 30 and a thousand milliseconds later answer will be the string, meaning of life 42.
asynquence
The last thing I want to do, I know we're overtime but it's the last thing I want to do, is I want to show you a library that I wrote called asynquence. I talked about it at the beginning of the day. Because there are some really great things about promises but there are also some really not so great things about them. In that they don't go far enough with some of their abstractions. And I think the future of promises is that most people will continue to use promises with abstraction libraries on top of them. Promises are a really, really low level mechanism and in some of your most simple use cases, like for instance this one, it's not too much difficult to use. But when you start to get into really complex, real world code, it starts to get really tedious to create these promises all over the place, and to figure out how to manually chain them together. When you start thinking about more complex tasks like what if it's not this then this then this? What if it's this and all of these things and then this thing and these two things, and then this thing except go back and start. What if you start having those sorts of flow control? Promises start to get really tedious. And that's why there are promises abstraction libraries to try to help some of that tedium. Try to take care of some of that tedium for you. There's a number of ones out there, there's async and queue and several other ones. I happen to have one that I think does a pretty good job of making things simple and it's called asynquence. Asynquence stands for asynchronous sequences. So sequences are automatically chained promises. If you'll notice in our previous promise examples, you had to manually create a new promise and return it from each step to keep the chain going. Whereas in most cases, you could just assume that somebody wants to keep going because there's always another step in your task. Most of the real world times it's a lot more than just one step. Asynquence assumes it and it automatically creates and chains promises for you. And here's a simple distillation of the code. You create yourself a sequence by calling the constructor the ASQ. You have your then steps because it's just a series of then steps but you'll notice you don't have to create promises here. It automatically creates a promise for you and it passes in the completion trigger. So it assumes that you're going to want to go on and it creates the promise for you, and you just need to make sure to call the trigger at the proper time. You don't have to do any of that work of creating those promises for these normal steps, it's created them underneath the covers. We also have the ability to do the other primitive and asynchronous flow control is what we call gates. Sequences are this then this then this then this. A gate says two or more things are going to happen at the same time and I don't care when they finish and in what order. I just want to wait for all of them to finish before I move on. It waits for everybody to get to the gates, it's an old school terminology from processes and fork and stuff. Asynquence lets you split from a sequence into a gate step back into a sequence. And you can express any, you know, arbitrary complexity of flow control using the asynquence API. For example, here's our little meaning of life example. I have rather than returning a promise I return it back a sequence. Here I can do what's called a waterfall which does these things in order but it keeps track of the messages. So it calculates 10, sends that along. It calculates 30 and it sends that along. 10 and 30 come in. We then calculate the meaning of life as x and y and we pass that one along. You can do the same sort of message passing, just has a lot less work because you don't have to create the promises every time. Finally, it was mentioned earlier what about generators and promises? I think that generators plus promises are actually the most popular pattern that we're going to move towards for asynchronous flow control. And I've got an API built into asynquence that handles this natively, it's called runner. It allows you to pass in a generator and yield out sequences or promises. It automatically, this little runner utility. When you yield that out, it will receive that promise, listen for the promise to complete before it starts back up the generator. It will automatically continue to the end for you. We would yield out a promise or a sequence, forget data and when that guy sends us the value back in then 10's going to come back in. Then we yield out another promise, a second later we get 30 back. We finally yield out a third promise for the string and a second later we get that answer back, and we can return that answer which then gets passed along, along the sequence chain. Finally, I just want to show you something cool because I just was starting to experiment with this. I actually think this is some unexplored territory here. The idea of taking two or more generators and interleaving their operation. Runner actually allows you to specify two or more generators and what will happen is the first one, the first time it yields, it will actually message past to this generator. And when this generator yields it will pass to the next one in a round-robin fashion. You can actually have these generators running at the same time starting and stopping and message passing to each other, which is going to lead to all kinds of powerful stuff. This is called CSP, Communicating Serial Processes. It's a model, it's a really advanced model for continuation style.
Quiz: Async Patterns
The bottom line takeaway is you can use promises natively or you can use any library that you're happy with. I think asynquence does a pretty good job of making it easy to deal with promises without all of the complexity, but you know, feel free to use it or not. Finishing up, what is callback hell? What is it really? Giving over control of your program. Exactly. It's inversion of control. It's handing your control of the rest of your program over to some of the utility and all of the trust that that involves, and all of the problems that it can introduce. The lack of error handling, the lack of retries, the lack of knowing if it's going to do it too many times or not enough or all of that. How do you pause a generator? What was the mechanism we used for pausing a generator? Yield. Yield. Yield and how do you resume it? Next. Next. .Next on the (mumbles). What is a Promise? Something that will eventually either be rejected or accepted. Yeah. Or may notify. It's a future value is what it's usually called. It's a promise for a future value. It's a continuation event. It's a transaction at Burger King, however you want to think about metaphorically. And how does it solve the inversion of control issue? Gives you back the ability to decide whether your code's going to be running or your continuation's going to be. That's right. Instead of passing my continuation in, I receive a promise back. So it uninverts that inversion of control. And it puts me back in control of deciding what step two looks like. Finally, how is that we could, what was the key characteristic that allowed us to combine generators and promises for async flow control? Remember, the generator's yielding out promises and the promise when it completes automatically restarting the generator. So the key characteristic was call a generator, have it yield out a promise and when that promise finishes, have the promise restart the generator. And most of the async flow libraries out there including asynquence have a utility for that. Some of them call it spawn, mine is called runner but it automatically listens for yielded out promises and it restarts the generator when they complete.
Exercise 5
Unfortunately I'm going to have to assign you yet another piece. I'd hope that we could get a chance to go through this. There is this exercise five, this is a brand new one that I just created so you guys are the first ones to see this. But I really encourage you to spend some time tonight playing with it because it's actually kind of fun. What the task is it requires you to, it's a fake AJAX load but it requires you to load up three separate files in parallel. You're going to try to get the contents of those files at the same time. You want to do it in parallel but it wants to make sure that you print them out in the proper order. And that's a deceptively simple sounding task, that's actually a little bit complex to figure out. So I've implemented it using callbacks and you can see how difficult it is to manage the state with nested callbacks. And then the challenge for you is using whatever promises or generator syntax you like, whatever library. I've shown you how to do it with asynquence and I've also shown you how to do it. There's files in there to do it with asynquence and also with native promises. But whichever format you want, I want you to try to solve that task. How could I load up three separate things but make sure they print in the proper order? Because that, you know, that is a real world sort of asynchronous task that we face in our code. I wish we had time to kind of talk through it. If you guys have questions about it, please feel free to email. We could maybe take 10 minutes tomorrow morning. Yeah, we'll probably go over the exercise. If you guys get a chance tonight, we'll probably go over the exercise, that's a good idea. Speaking of tomorrow, tomorrow is going to look somewhat different than today in terms of the style of the way the class goes. So just to prepare you guys as you're packing up. The style for tomorrow is going to be a lot more code and a lot less lecture, and that may or may not be what you're hoping for. But there will be a lot less slides, a lot less of me sort of standing for long periods of time and talking, and we're going to do a lot more tinkering at the codes. So you're going to write real world node code and the goal is to take what we learn today as a foundation of confidence so that we can write code in our node JS processes without worrying about how these mechanisms work. We'll revisit asynchronicity and we'll revisit a whole bunch of these other things as we deal with them, okay? I appreciate everybody's time today and all your great questions and participation. I look forward to tomorrow, to the second day. You have any question let me know but I appreciate it very much.
Exercise 5 Solution
Now just as a caveat to exercise five, there's some deceptive things to this exercise because it seems at first blush that what I'm asking you do is pretty straight forward. But it's what, it's as they say it's the devils in the details. When you'd start to think about the implications of this code, you start to realize it's a little more complicated than you might be aware. Asking you to do this exercise from scratch if you've never done anything with promises is a tall order. So I provided the solution already using the callback approach. This is a complete program that uses the callback pattern if you were to run this code, if we were to open up exercise five, ex5.html and we are to run it, you'll note here in my console. Well, it's locked up on me for a second so just a moment. Okay, so watch particularly not the requesting comments because if those in there just for debugging purposes, but watch particularly how I'm printing out first text, middle text, last text and then complete, making sure that it's in that order. But watch the timings on these things because I have this set up to fake like they are randomly taking longer, different files taking different longer. Technically the files quote, unquote "load at different times." But the mechanism that I've put in place makes sure that they always get printed out in the correct order. Here, we may see, if I get lucky, we may see examples where in this particular case it looks like it's waiting for all of them to finish because maybe the first one was the long poll in terms of delay. But if we get lucky we might see the text peppering in one at a time depending on my random number generator. There you saw just a little bit of a delay where the first and the seconds ones are printed. It was still waiting for the last one. The spirit of this exercise is you do want to make sure they go in the correct order but you don't want to have to wait for all of them to finish before you start rendering. If the first one comes back quickly render it right away. Kind of in the same mindset as we take progressive rendering, show things as quickly as possible. If I get lucky we'll get a random choice here where it will actually print out the first one very early with kind of a very short delay. And then you'll see in, so there's one it's still waiting on the second one. And then it waited just another millisecond for the last one. The mechanism that we put into place to make sure that they stay in the proper order requires us to track some state in between three independent sets of actions. Because we need to request them all at once but they need to modify some shared state so that we know when all the responses have come back and we know when the first one has come back that we can render it. But if the second one comes back first we need to be still waiting on the first. The point of this is that asynchronicity oftentimes requires you to track additional state between your separate actions. In this case, the loading of the files. Now I'm just faking it. This is a fake AJAX that just sets up a random delay between one and nine seconds long. I immediately print out that we're requesting it but I just set up a timeout and then send you the information back. So we're faking an AJAX and we're faking the contents of these files but you could easily extrapolate that these could be real AJAX calls that on the network might have different timings, depending on net recognitions and so forth. Here's how I call that, I call that fake AJAX. I give it a file name that I want to request and I set myself up with a callback. I want to be notified when it happens. And I've decided to have one callback that gets called for every single one, that's called file received. This one gets called when all three of them are called and we're going to internally track a state in a variable that we call responses for the responses that have come back. And so, each time we get a new response that we didn't have before we add it to our internal state. And then we loop through our responses to figure out if there's one that we can render yet. So we start at the beginning and we say do we have response one? If so, render it. And then when we get to two, we can't render two unless one was already rendered. So we just do a simple for loop through our state tracker to see whether or not it's okay to output. And then finally if we haven't had any cases where the responses were missing then we know that it's time to go ahead and print out the complete message, okay? Now there's a thousand different ways that you could track the internal state, this is not the only way. I just wanted to show using the callback mechanism we are forced to track this internal state or track the state between our different tasks independent because we want to request these things at the same time. We don't want to wait for file one to finish before we request file two and so forth. And even if you're not dealing with file loading this is still a very common thing. You may have database request where you want to fire off three database requests to three different tables. You don't know what order they're going to come in but you need to make sure that you order the responses in your JSON object properly. You need to make sure that they go into the correct slots. This is the kind of problem that seems to crop up an awful lot in asynchronous flow control. And before promises, many of us just hand rolled our own solutions similar to things like this. And the purpose of this exercise, if you've never done anything with promises is to sort of explore. You may be confident enough to try to write your own code if you've looked at some promise code before or you may feel like I just want to study the existing code. That's what we're going to do here. I'm just going to show you using first my library and then I'm going to show you the same way using native promises. I want to show you one way that we could do it using asynquence. The same utilities is true before we have a fake AJAX. That's going to receive a callback, we have our output function, all that stuff stays the same. The stuff that changes is the stuff that's underneath these little stars here. All right, so I set myself up with a different kind of utility. In the previous one I called it getFile and he used callback methodology. But here my getFile is going to do something different. I'm going to set up an asynquence. I'm going to set up a sequence which is essentially like setting up a promise. And when that promise, and when that fake AJAX calls my callback that will notify my promise that it has been completed. But I'm returning my promise back so that I'll be able to chain off of that. I'll be able to listen for that continuation event if you remember from yesterday. Now I want to make sure I call all the files in parallel. So, technically it may look like I'm calling them one at a time but because each one of these is an actual function call, I will request all three functions right away. I mean all three files right away. Now the getFile function, every time we call it returns back a different promise, a different sequence. I'm going to have three different promises that I'm going to slot into a sequence of steps. And you'll note here that the way the sequence is written, it makes it very clear the behavior that we want. It's a very declarative style of expressing our asynchronous flow control because I'm saying when file one finishes loading then I want you to go ahead and output file one. And when file two finishes loading output file two now. If file two finishes early, if it finishes before file one, that promise just sits there and waits for us. Because promises will track that internal state that they have been completed early before we've listened to them. That's one of the functionalities that promises give us. Even if file two finishes, even if file three finishes before file one, because we've expressed this in a chain, a series of things that we want the steps to happen sequentially, then we know that file two will be loading and we'll make sure to wait. If file two is not there by the time we get to it then we just pause the chain. But if it is we go on and the same for file three. Expressing code like this allows a developer I think to reason about their asynchronous flow control in a much more reasonable way than in the previous code snippet. They functionally do the same thing. They're functionally tracking the same sorts of state but in a very different way and they produce a different source program. I think I said this yesterday but if I didn't it's there is repeating. Source code is not written for computers. Source code is written for developers. The computer only cares about ones and zeroes and there is literally an almost infinite number of source code programs that could produce the same exact series of ones and zeroes. You're not choosing to write source code because you want to help the computer. You're choosing the right source code in a particular way because you want to help yourself and your other team members. When we write this asynchronous flow control, the goal is to write it in such a way that it makes it easier for us to maintain mentally, to understand to look at this code. And I think asynquence does a pretty good job of that. You might not, it's okay. I'll show you the native promise approach to it and you see whether or not you feel like that's a better way. In this particular way we've created ourselves a chain, it's very clear what our steps are going to look like. And if there's ever some problem we know exactly where in that chain to go looking. Now if I, yeah? So when we say we are going to get all these files in parallel right? The files will be requested in parallels. But the .sync will ensure that the promises are chained in sequence? Yes. Sure. Okay, okay. That's exactly what it's doing, it's making sure that things will go in a sequential order of series. But the files are requesting. Mm-hmm. And so if file two comes back well before file one there's something that needs to track the internal state of that and we've chosen to let the promise do that rather than what we were doing in the previous file where we had to have some data structured to track that stuff, okay? Now, if we wanted to just use the plain old native promises, no promise, abstractions, no anything, what would that look like? Again, the stuff at the top is completely the same. The only stuff that's going to change we have our getFile which it should look almost identical to the previous one, we're going to construct a promise object rather than to construct a sequence. That part starts to look pretty much the same. We call the result function on it. But here's where things start to get a little different because we don't have quite as much sugar built into the native promises. Things aren't going to be quite as pretty. They'll still functionally work but they're not quite as pretty. The first thing you'll note is that really the only way practically to do this something in parallel is to call all these methods literally in parallel and we need to track those promises individually. Because there's no API like I've built into asynquence to automatically bring those three promises into a sequence like that. There's no facility for that directly. I have a promise one, a promise two and a promise three that ensures that I've made my requests in parallel. And here's how I chain them together. I take advantage that the first one is a promise, so I can call the then method directly on the first promise and do an output. And then after that output's done, it would have been nice if kind of like we did with a sequence if there was a sugar that would allow me to pass that promise directly into the chain. But unfortunately the native promises don't allow that so we have to do a little function that returns our promise, okay? That will chain the promise two into this part of the chain and then an output and then chain promise three into this part of the chain and then an output. Still functionally it's pretty similar in terms of being able to reason about it. A little bit less sugar. The comparison there is to give you that abstraction libraries provide you better sugar which gets more and more of the croft out of the way and lets you focus more of your attention on the things that you actually care about rather than on the croft, okay? But either way using the built in one or using a library, it's pretty reasonable to express this in a promises mindset. Just real briefly I want to show you this is going to look a lot more complex but it's actually going to betray that there's a whole lot more power under the covers than what we're doing. Because what if this wasn't a preset number of promises that we knew about? What if we were loading potentially hundreds of files or potentially hundreds of database requests. We didn't really know how many there were. You couldn't practically write out p one through p a thousand and manage that code. How would we do this in a way that could use utilities that have looping capabilities and so forth? We can use the array functionalities of map and reduce to solve those problems pretty nicely. Again, I will first show you using the asynquence approach. Using the asynquence approach, what I'm going to do is I'm going to have an array of these things. In this case it's still just three but it could be an array of a thousand of them. I'm going to use the map function which map if you don't know what it does, it takes an array, it runs a function against each element in the array. And whatever that function returns replaces the original element. It's doing a one to one mapping of elements in array from one thing to a transformed version. In this case, you know, sometimes people do that to like transform a bunch of strings to upper case or something like that. In this case, I'm going to transform the first array of strings which are file names, into an array of promises. Basically an array of sequences. That's why I'm calling .map getFile. Remember getFile takes an input and it returns an output. That's exactly what we want. We want a function that takes something in and returns a replacement. We can just call map getFile and that will now leave us if we were to inspect that in a console, we would now instead of having an array of strings, we'd have an array of three asynquence promises. Okay? Now, I'm going to call map again on that array so I'm going to do another level of doing it. I'm going to be taking in sequence for each one of the elements in the array and what I'm going to do is tack on chain on an output to each one of those promises. I've created essentially through a looping mechanism the exact same thing that we did manually with the one, two and three in our previous code snippet. I take that full array, that complete array that's been produced from that which is now an array of promises that are loading in parallel but they've got their outputs chained in the proper order. And I pass all of that array into my asynquence API using the normal apply approach that you would have available to you. And finally the output works. This code works and this is more flexible, it's more powerful to us now because we don't have to manually code our sequence. We can take advantage of looping. Finally, how would we do the same sort of technique, how would we do it with promises. It looks similar but it's going to be a little bit different because again, the native promises don't have quite as much sugar to them. Again, everything at the top's the same, our getFile is the same. The only thing that's going to change down here, the first thing that we're going to do is we're going to do an array of our elements and we're going to do a map getFile just like we did before. But now because we're not using a sequence and we don't have some of that sugar, we're going to need to do a little bit more work to massage what we're doing. So we're going to call a reduce function rather than another map function. And I won't get into all the details of reduce but reduce starts with an initial state of an element and it passes that in for each element, and the idea is that you sort of add on or chain on. In this case we're going to start with a promise and we're going to for each element in our array we're going to chain on our promise to that, and pass the chain along. At the end, we get one big chain that has all of our promises chained together and we used reduced to do that. And then of course finally we call then to output our complete. Hopefully that provides you some good code to kind of go back and look at and compare yourself as you're starting to try to think about promises. You can kind of get a sense of doing things kind of the manual way which produces nice, pretty-looking code. But you also have the power to use these looping constructs in a pretty powerful way as well. Any questions about that exercise before we move on? Is promise similar to threads, say a new (mumbles) thread safety issues? There are no thread, the question was is promises similar to threads or thread safety? There are no threads in JavaScript. JavaScript is a single threaded language. The model for concurrency in JavaScript is called the event loop which means only one piece of code can be running on the JavaScript engine at any given time. And it just, you put yourself on the end of the queue and then your function gets run. We don't have any worries about thread safety, we do have shared memory. We do have that issue in concurrency and promises kind of not really completely reduce the idea of shared memory, but they go more towards a functional nature where there isn't a shared memory block that you're managing. You're managing state inside of each promise. The fact that you have a bunch of promises chained together is what manages the state rather than having some big global variable that everybody modifies concurrently. Okay, no issues of lags or anything you know? That's just not, it's just not possible in JavaScript to produce that kind of mechanism, so. Yeah? It's a question from Derick A., is your coding style a specific pattern with regards to dropping the dots and chaining methods like this or is that just a personal habit? It's to make things easier for you to read. It's not really even a particular style that you should do. I tried to make it easier to read when I'm illustrating things for people. I'm trying to make it clear that this is a separate chain from that but there's no-- But it's allowed in the language because it's waiting around to see, like the statement doesn't end until a semicolon, right? Correct. Is that why it's allowed? Yeah. It's pretty common, that's an idiomatic style that comes kind of from jQuery world. It's pretty common that you put each chain element on its own line or whatever. We have another question. Yeah. Do you plan on covering promises and async in the fourth coming async performance chapter of You Don't Know JavaScript? It's a full book not just a chapter but yes. The async and performance book is going to heavily deal with promises, generators, co-routines, all that stuff. And your async library? Asynquence? And asynquence, yes. The typical style that I've tried to do is in these books the main chapters of the book deal with the core stuff that we know about the language or that we know about. And then I would probably use an appendix to discuss my own library. Okay. I think that's it for what we're going to go through on those old exercises. Again, if you run across any other questions at any time, it's kind of an open invitation to everybody that takes a workshop with me, as you go through this a month from now or six months from now, if you have questions feel free to reach out. There's a lot of exploration and things like that. I'm not saying I have it perfect or right, it's just to get you going thinking about this sort of stuff. Yeah? Where is the context by the time you get to that last stem? In which file? Just that last one like. The promises one? Yeah, what's your this at the end? We're not dealing with any this style coding at all. I actually don't really like this style coding. Remember, I said 95% of the time I use kind of the lexical model for coding. So promises don't really stress anything about a this binding, and I completely avoid that topic entirely in asynquence. There's no this binding at all.
Course author
Kyle Simpson
Kyle is a freelance developer based in Austin, TX. He runs several open-source projects (such as LabJS), writes books, and speaks at meetups and conferences.
Course info
LevelAdvanced
Rating
(2129)
My rating
Duration6h 55m
Released10 Apr 2015
Share course