 Hi, welcome to OpenJS. We're gonna talk about JavaScript to grumpy parts. JavaScript is kind of weird But well, let's dig in and see how it works and see if we can understand why it's weird and make it a little bit less mysterious Here's the part where I tell you I'm definitely gonna post the slides on my site tonight. And well, they're already there I've been the person chasing the the Speaker as well. And yeah, here's JavaScript grumpy parts. The slides are online right now While you're here on robridge.org click on about me and you'll get to this spot That talks a little bit about the things that I do I'm a Microsoft MVP a friend of redgate a cyro developer evangelist and let me tell you about AZ give camp a z give camp brings volunteer developers together with charities to build free software We start Friday after work Sunday afternoon. We deliver that completed software to the charities sleep is optional caffeine provided If you're in Phoenix come join us for the next AZ give camp or if you'd like a give camp where you're connecting from hit me up On email or on Twitter and let's get a give camp in your neighborhood, too some of the other things that I've done I worked on the gulp team as a core contributor in version 2 and version 3 and Dot net rocks. I replied to a dot net rocks podcast episode. They read my comment on the air and they sent me mug So there's my claim to fame my coveted dot net rocks mug So let's dig into JavaScript the grumpy parts Now we will need to go a little fast because well, we only have a half hour together But I would like to thank John Mills He has a talk a job a guide to JavaScript's Gary side that helped inspire this talk now He goes into different directions, but his talk is amazing. And so if you have a chance listen to him as well We'll probably hit the end of my knowledge and that'll be really fun. I look forward to The part where I say I don't know In the beginning Brendan Ike created JavaScript in 10 days 25 years ago I've written some code 25 years ago, and it was pretty awful and yet here We all are talking about JavaScript Brendan did an amazing job if you'd like to learn more about Brendan read more or watch more to see how he invented JavaScript, it's really cool. Each of these blue links in the slides here from robertsch.org are links to be able to dial into additional information Now what's really cool is we now have a bunch of JavaScript engines that are for the most part really high fidelity in V8 we have Chrome in spider monkey. We have Firefox in in Internet Explorer, we have Chakra in Safari we have JavaScript core and Each of these JavaScript engines works pretty much the same Brendan Ike's library was cloned with amazing fidelity now We talk about differences between JavaScript in different browsers HTML5 has made that a little bit less of a concern But that was about our interaction with the document object model the DOM the JavaScript runtime itself is Amazingly compatible including all the bugs So JavaScript was copied with incredible precision including the bugs Let's take a look at some of the weird things now some of the major design goals of this language Was it was a language that well runs over there when we develop JavaScript? We ship our source code a .js file the browser is the one that compiles that JS code into executable and runs it now that isn't quite right, but we can use that analogy it Runs over there after the developer has left. So one of its primary objectives is to keep running as often as possible Now if it keeps running It's gonna try to be as forgiving as possible so well if it notices a syntax error It'll back up and see if it can put a semicolon in to be able to solve that Now are semicolons required in JavaScript? Well, yes, they are But the engine may insert them automatically. So if you see JavaScript without semicolons That's why we're leveraging that piece of the compiler that says hey, let me fix that for you So let's take a look at some of the weird things in JavaScript This is the JavaScript Watt talk and I'm not gonna play it for you But I invite you to grab these slides from robritch.org and click play. What's particularly cool Is this is Brendan Eich playing the JavaScript Watt talk at one of his talks and his commentary throughout it? It is amazing So let's take a look at some weird things undefined well undefined is just a variable. So what if we define it? in more recent versions of JavaScript of ECMAScript it is defined as a constant so we can't override it But this led to some really really interesting bugs if sir for example, we defined JavaScript type of null Type of null is an object. Hmm Should it be null? Should it be an object? This is probably one of those bugs Brendan I created it in 10 days and a few weeks after that he said, you know, there's some bugs here I'd like to come back and fix and he was told hey There's 40 developers already building with JavaScript right now. We need to not change it. That would be backwards incompatible 40 developers hmm I bet there's 40 developers in this room that wish we had gone back and fixed it But he made the best decision that he could at the time Here's another one type of nan. Well, not a number is well a number. I Get that not a number is kind of in the number group It's more in the number group then say in the date group or the object group or the function group But not a number being a number. Yeah, that's kind of weird So these are some of the weird things in JavaScript And let's see if we can dig in and understand how they came to be and why they are that way Now first up, let's take a look at the JavaScript compiler Now I grant that in modern JavaScript engines. We have mechanisms for code split Treeshaking and just in time compilation and those are amazing But at its core JavaScript is a two phase compiler The first phase goes and looks for variable declarations And it kind of sets aside that memory for those variables the next phase is to run the code Now because JavaScript has this two phase compiler Then we can use that knowledge to understand some code and really dig in deep If you'd like to learn more about the two phase compiler I would invite you to click through to the slides at robrich.org and click to read more or watch more So let's take a look at this code What's it gonna do? Let's think like the compiler and see if we can figure it out Now the first phase we go look for variable declarations Here's one var foo equals bar. Okay, so we're not setting it to bar yet That would be the execution phase, but we are declaring this variable var foo Next phase, let's go execute the code. So we start out declaring this function, then we'll call it So we'll start off and we'll console log foo Well, we already have this foo variable declared We haven't set its value yet. So we get undefined If true now variables in JavaScript by default are Function scoped not curly brace scoped. So we know that this foo variable exists out here Now we're gonna set it to bar and then we'll leave the curly braces This variable continues on and we console log bar. So we get undefined and bar So in our minds, we've kind of tricked ourselves to believing that the variables get hoisted It makes sense to believe that well, we just kind of move this variable declaration up here and we set it to undefined Now that variable hoisting is a cool lie that we tell ourselves But that's not actually how it works. How it works is this two phase compiler Yes variable hoisting It's a lie. It's a convenient lie and it helps us to think about this in kind of a more synchronous way Without having to separate that two phase compiler mechanism Now that's interesting, but well, it is a lie It's a very convenient lie and I like it, but hoisting is a lie So as we think like the compiler we can see how that variable hoisting it isn't actually moved rather it's well It's a two phase compiler So we saw this code and we saw how we could execute it in interesting ways Let's take a look at defining and not defining variables in various scopes Now we had a mechanism before where we declared some foo variables Let's declare this foo variable and this foo variable Take a minute to pause the video and think through this. What will it do? Now let's think like the compiler and figure it out first phase. We go look for variable declarations We find this one foo. So let's declare that one. We find this one. Let's declare that one Now variables are declared with function scope So we have two different foo variables in different scopes an inner foo and an outer foo if you will Now second phase. Let's run the code. So let's take this outer foo and set it to bar We'll declare this function. We'll call that function and now we declare this inner foo and set it to Baz Now if true now the curly braces don't define scope in JavaScript Variables are scoped to functions. So we go looking for this foo variable to set it to BAM Is there a foo variable in the scope? Yes, there is right here foo So we set it from Baz to BAM and we'll console log BAM We leave the curly brace scope Functions are functions to find the scope and so now we console log foo and we get this BAM again We leave our function and now we need to find this outer variable. Is there a variable to find in this scope? Yes, there is right here. So we'll output BAM BAM and bar. Is that what you got? Let's change this up a little bit instead of declaring the variable here. Let's declare it here Stop the video here. How does this work? Let's think like the compiler and figure it out. Our first phase is to define all of the variables Define this one to find that one and the second phase is to execute this So we'll set our outer foo to bar. We'll call our function set our inner foo to Baz. Wait a minute Where do we get this inner foo? Well, we go looking for variables in the current scope. Here's one This variable is defined as a function based variable. So We'll set it to Baz Then we'll set it to BAM. We'll console log BAM. We'll console log BAM again and As we leave the function then we console log bar BAM BAM bar. Is that what you got? Let's do it again, but instead we won't declare these variables at all Okay, first step. Let's go look for Variables to declare. Here's a variable. Let's declare that one Second phase. Let's go execute it. Okay, so let's set this variable to bar Let's call our function and we go looking for a foo variable. Is there a foo variable in the current scope? There isn't so we walk up scopes JavaScript is trying to help us Of course, the code is running over there once the user once the developer has left So we go looking up scopes. Oh, here's a foo variable. Let's use this one So where it was bar it is now Baz Let's do that again and where it was Baz. It is now BAM So we'll console log BAM and BAM as we leave our function We now console log the foo in the outer scope. Do we have a foo in this outer scope? Yes, we have this one that we set to BAM. So we get BAM BAM BAM Ooh Flintstones Let's do it again, but in this case, let's not declare it at all pause the video and figure out what happens here Now let's think like the compiler and figure it out first phase. Let's go define all of our variables. There aren't any Second phase. Let's go execute So foo equals bar. Is there a foo variable in the scope? There isn't let's climb up the scope Well, in this case, we'll climb all the way up to the global scope and we will define a variable there JavaScript is trying to help us succeed and so we define a global variable foo and Set its value to bar Now let's call our function Do we have a foo variable set in this scope? We don't so let's climb up the scopes until we get to that global Variable that we built for here and we'll set that to BAS Let's go find that variable again set it to BAM BAM BAM. We leave here and we log BAM again Now that's interesting JavaScript helped us by declaring a global variable But well, what if that variable was called I and what if you used it and I used it? Now we may overwrite each other. It is after all a global variable JavaScript tried to help our code succeed, but it may have done us a disservice by Just automatically creating a variable Let's do this again, but now let's set foo to BAM Pause the video here see what happens Now let's think like the compiler and figure it out first step. Let's define this foo variable Second step. Let's execute. We'll set foo to bar. We'll call our function foo. Is there a foo defined in this scope? There is not. Okay. Here's a foo. So let's set it from bar to BAS Now we'll set it to BAM. Is there a BAM variable defined in here? There is not How about in this scope? Nope. Let's keep climbing up the scopes until we find it Well, we didn't find it So how do we get its variable its value? We don't have a variable to get its value out of so we get a reference error BAM is not defined Now we could set a new variable correctly, but we could not get a new variable Yeah, that is kind of weird, but as we think like the compiler it makes sense We can't read from a variable that doesn't exist But JavaScript is going to try to help our code succeed So it will go create variables and set them if they aren't defined. All's being equal I'd rather it just threw an exception. Well, kind of. I'd rather it threw an exception while I was developing it But out there in the wild Yeah, I'd rather my user be able to continue on as much as they could So let's do it again Now we've defined variables here with var, but let's switch it up to let now let is new in ES6 or ES 2015 and let is defined as bound to curly braces instead of bound to function scope Pause pause the video here and see what happens Now let's think like the compiler and figure it out first. We need to go define all of our variables Here's one and here's one next. Let's execute. Let's set the outer food to bar Then let's call our function Now we're looking for a foo variable. Is there a foo variable defined in this scope? No, this let means that this variable is defined to an inner scope So we go looking for another foo variable in an outer scope. Oh, there's one right here So we'll change it from bar to baths Then inside of our if block, let's create a new variable and we'll set that to BAM So let's console log BAM inside here, then let's console log this variable Well, we don't have one defined in this scope, but we have one defined in the outer scope So here we will output baths BAM baths and then out here We're looking for this variable and we'll output baths again BAM baths baths great Now let's not define the variable Okay Let's think like the compiler and see if we can figure it out first. We declare our all our variables There's just one right here second we'll execute We'll call our function. We'll go looking for a variable. There isn't one in this scope There isn't one in the outer scope So we define a new global variable called foo and set its value to baths Inside this if block we have this curly brace scope variable So we output BAM and then baths and then out here we go looking for a variable in the current scope We don't find it We climb up the tree until we get to that same global variable defined here and we output baths Wait a minute Did this variable leak outside the function? Well, yeah Because we didn't define it scoped to anything it was created as a global variable That's weird, but well JavaScript helped us and when it helped us it created a mechanism where our code would continue to run Even if it's in a little bit of an unexpected way Let's do it again, but let's define these two variables here What happens in this case? Let's think like the compiler Well, everything works well inside this function once we get out here We're going to get to this foo variable and we're going to go look for a global foo variable Well, there's no variable defined in this scope. Let's keep looking for a global variable Nothing was defined here because all these variables were defined So we get a reference area foo is not defined foo is not defined because well Because I define these variables inside this containing function then they expired once we left that scope Let's do it again, but let's switch from Let to const Now const in ES6 is a variable that can't change now the contents of that object can change But the variable itself cannot So let's dig in and take a look Well We define our variable we call into our function and Now we're looking for a variable called foo in the current scope This one is an inner scope so we can't grab that one So we go looking for this outer scope and we go try to set it. Oh, we can't set a constant So we get assignment to a constant variable Now if we're using babel to transpile from ES6 to ES5 where cons doesn't exist Then it changes this const to a let or no it changes a const to a var and Yes, we can't assign a var. So we'll get different behavior Every evergreen browser supports ES6 or better now So probably we want to turn down babel to output ES6 or better and ensure that that const is indeed const But that's why you might get different behavior inside of Babel so we took a look at defining variables. Let's take a look at this What is this? Well, it's the thing to the left of the dot Let's take a look at some examples and we have this speak function where we console log this dot name Now we're defining name out here in a global way. Well global to this space So if we call speak what is the thing to the left of the dot? Well Global so we get ninja now. Let's call obj one dot speak We could definitely have created this speak function in the middle here But I just copied it into place for each of the objects. So obj one dot speak What is the thing to the left of the dot? Well, it's obj one. So we get doctor Obj two dot speak we get Skywalker perfect ninja doctor Skywalker Let's do it again, but let's Grab it out as a function now in this case. It's no longer the thing to the left of the dot or Rather the thing to the left of the dot is global. So Obj one dot speak will work correctly. We'll get doctor obj dot speak. We'll get undefined We didn't define a global name hmm So let's create a new mechanism where we can go grab a button now We grab it by ID and then we click the button to call the speak function Now what's the thing to the left of the dot? Well, it's the button So when I say this dot ID knowing that I have a get element by ID, I'm going to output the button Perfect Now what if we want to change the speak function to output the name in a hundred milliseconds instead? Okay, so let's do it now when we call obj one dot speak Set timeout is going to create a whole new stack. So what is this in this new stack? Well, it's the global function. So we're going to get ninja twice hmm Let's see if we can fix that we can alter what this means by calling dot call Now we'll say dot call and we'll pass in what we want this to be So taking a look at this code obj one dot speak obviously works as expected But we don't have a speak function in obj two So we'll say obj one dot speak dot call and set this to be obj two Now this is set to be obj two. We've overridden it and so we'll get doctor and Skywalker great Well, let's do that same mechanism We'll say dot call this to try and fix our problem here with our set timeout Now it's gonna say dot call, but this executes it right away So we will get the right answer ninja and doctor, but we didn't wait the necessary hundred milliseconds Let's look at bind now bind is a great way to create a closure a new function that has this set the way We expect we can kind of think of it like this. This isn't the correct syntax But we can think of it this way. Let's pass in a function and what we want this to be We'll return a new function. We'll say function dot call with that set Now we have this new function that we can call whenever we're ready and that will actually do the function calling So let's look at the real syntax obj one dot speak dot bind obj two Okay, so because we're saying bind we get this new obj two speak function And we can call it later and this is already bound to obj two. So we get doctor and Skywalker perfect Now we'll probably see in our code obj two dot speak dot bind obj two a lot What it's trying to do is saying I want to set this. I don't want any ambiguity That's perfect. If you find that in your code. That's exactly what it's doing Now let's come back to our set timeout function and let's call dot bind this now dot bind this will return a new function that We can call later say in a hundred milliseconds So now that we called dot bind well We've got ninja and doctor it works correctly very nice Now let's change to an arrow function Now what an arrow function does is it binds the variables at the point where the function is defined We can think of it kind of like this So let's define this function bind it the way we expect and let's see how this goes So we've got this speak function and we'll turn it into an arrow function Now because it binds at the point where it's created then well This is bound to the global scope at the point where it's created we get ninja ninja ninja oops That isn't what we expected. Okay, so let's say obj 2 dot speak dot bind obj 2 We have this trick that allows us to bind this well Kind of this is already bound into place So wrapping it in another function that binds it to something else then when it calls this inner function It's already bound so we can't Rebind it so yeah Nope that didn't work Okay, so here in our function, let's use an arrow function here We know that it binds at the point where it's created So let's use that to grab the this and now yes ninja doctor it works as expected perfect Now what if we changed speak to be an arrow function? Well, then it wouldn't behave as expected now it would bind to the global this But because we have this outer one as function and this inner one is an arrow function it behaves as expected Now that's a little weird knowing that arrow functions bind at the point where they're created Will help us to understand a little bit about how it works. We shouldn't just change every function to be an arrow function That would be well To bind this too much and we've seen that we can't override it Now let's briefly take a look at the event loop. I Love this website where we get to look at how the event loop works Let's open this in a new tab and flip over to that tab and we can take a look at this. This video is awesome Now we have some code here and we have the call stack what it's running right now a callback queue and web APIs For example, I'm waiting for a database or a rest call to complete So let's copy this code and we'll go set it in place and take a look at how it works save and run Now we start out with that set time out. Okay now it's counting for i equals 1 to 3 and it's counting and It's setting new content up here to finish once that finishes It comes back down here into the callback queue that as the call stack empties It goes and grabs the next thing from the callback queue and sets it in place Now this highlights that great scenario where what is it outputting? Well, it's outputting the current i What is the i by the time it gets here? Well, it's um 3 So we're gonna console log 3 three times But we get a sense for the call stack the callback queue web APIs It is a perfect mechanism for being able to visualize those three pieces. I Would invite you to play with that site because it is really really fun So we've got that stack where as the content is run It's gonna run through all of the pieces in the stack It's not gonna look at anything in the callback queue until the stack is empty Once the stack is empty it will grab the next piece from the callback queue and set it on the stack and process it Read more or watch more about this and learn some more about it Now as we look at node we can think of it like this Now this isn't the physical layout, but this is a good logical layout each request has its own stack and callback queue and the things that it's waiting for Now as node goes through it looks at each request and gets it a little bit farther Well, what if this request is gonna count from one to a billion? Well, then the the callback queue can't get further So we'll not we'll want to do a lot of things to get to yield the thread as much as possible So that the other tasks have a a chance to get caught up and then we'll come back and and Compute a few more So we might see something like this set time at zero. Well, why would I wait zero seconds? well Because we're trying to yield the thread so that the rest of their requests can get caught up We might also do this process.next tick and in more modern versions of node We don't even need the empty function here We can just say await process.next tick and now we've yielded the thread for a second and let everybody else catch up That is perfect. Now if there's no other requests that need any attention It will come back to us nearly immediately and continue on Async and await now. We only have a minute. So let's cruise through this really fast Async and await was clearly borrowed from C-sharp. It builds a similar state machine as As the task parallel library in C-sharp, but it does it with promises and Generators So well, what if we have this promise-based library here and we want to upgrade some of the things to async and await How do we do that? Well, the cool part is that async and await has this mechanism where we can just await things and start to feel as if it was Synchronous that's amazing Now because it feels synchronous We can start to think about it with you know standard fallback mechanisms But we know it'll stop here until this is done and it'll stop here until this is done and it's not blocking the thread It's yielding the thread for other things and then when it comes back then it'll be able to continue on We can think a lot more synchronously in spite of the fact that it's actually executing asynchronously That's amazing Now do we have to wait until we do a big bang refactor to get everything? Nope Async and await works as promises under the hood So we have this async function and let's call it but not await it What is res? Well res is a promise that we can just dot then with Now we could choose to await it so that we would resolve the promise But knowing that it is a promise under the hood we could dot then So let's imagine that I have this legacy function that I need to call from this new async code that I'm writing Do I have to use promises and a dot thenathon? No, I can just well await that function I Know how to await promises and it works just fine Simultaneously if we go the other way then we can take a look at this async function and call it using Promises now in this case we would like to do a lot of things in parallel Now we want to call it one call it to notice how we're not awaiting them. So we have three promises Well, how do we await a bunch of promises? We have this promise dot all And we can await that and then we have all our results all these things happen simultaneously Well kind of JavaScript is still single threaded, but I didn't have to wait for one to finish before I started to That's perfect JavaScript it's an amazing experience for a 10-day project 25 years ago I think Brandon Ike did an amazing job The code I wrote 25 years ago is not nearly as good as the code he wrote 25 years ago Find me in that place that the conference has designated for Q&A or if you're watching this later Hit me up on Twitter at Rob underscore rich you can grab the slides right now from Rob rich org Thanks for watching