What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Code School: JavaScript Best Practices
by Jason Millhouse
Become a more informed, conscientious user of JavaScript as you explore time-tested, useful techniques that will improve legibility, performance quality, and safety in your scripts.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Recommended
The Sword of Syntax
Ternary Conditionals
Hi, friends, and welcome to JavaScript Best Practices. This short collection of tips and tricks, do and don'ts, is intended to accomplish two things for you, the JavaScript developer. First, is to help you become fluent in and cognizant of the available constructs within the JavaScript language and to help you use good judgment when you engage with those tools. The second thing is to, of course, help you build the safety, the performance, and the quality of your applications in large and small ways, not just for your users, but also for you, as the developer. And with that, it's time to move forward with your journey. Welcome to the land of best practices. Find the sword of syntax first For the useful tools that you may need Wear the pendant of performance For efficiency and speed Caution's Crystal clears the sky With triple equals And try catch avoiding stuff that sucks In parsing better numbers on a stretch At last the golden shining mail of modularity When named please close your imports Long dependent integrity For polished skills in JavaScript The treasure trove this is Now raise your sword and strike your shield With these best practices Hello, travelers, and welcome to this, the first portion of your journey through the land of JavaScript best practices. In this first level, we'll be examining alternate methods of syntax that will help you organize lengthier bits of conditional code into more concise, informative, and legible blocks of functionality. Cultivating a thorough knowledge of what's even available to you within the JavaScript language helps you become a move versatile, a well-rounded developer, especially when you might see these constructs out there in the wilds or even just in code that you were hired to maintain but that you didn't build yourself. Now, as with any tool, there are good uses and not so good uses. And we'll do our best to provide you with your best bets while we bring you up to speed and with that it is time to tackle the ternary conditional, logical assignments, and the switch block. In order to do that we're going to take first a look at the standard conditional block. The first thing we'll do here to set up our conditional block is to declare a variable called isArthur and we're going to set that equal to false. Next we'll declare a weapon variable. Then in our conditional block we'll say if isArthur, we're going to assign that weapon variable to be Excalibur. Otherwise, if it's not Arthur then we're going to assign Longsword to that weapon variable. Now what you should notice here is that this sort of takes two blocks of code just to get one assignment finished. That's sort of a little long in terms of code length. So let's see what we can do about using a syntax trick that will make this significantly more concise. To build a ternary conditional, the first thing you'll do is place a condition down at the front of your ternary conditional build. Following that condition is going to be a question mark operator. That's going to divide the ternary conditional into the condition and the actions to take. Next up, you're going to have a pair of expressions that follow that question mark. These are going to be separated by a colon. One of these will be picked as the conditional's result. As you can see if the condition is true, then we will get this left side of the colon as a result and if the condition's false, we're going to go ahead and get the right side. So let's see how our current conditional block can translate into the ternary conditional format. You can see here we're going to stick our condition, which isArthur single variable with Boolean value. Then on the left hand side of the colon, we're going to put Excalibur because that is what we want to be the weapon if isArthur is true. On the right hand side, we're going to put Longsword. That's what should happen if isArthur is false. Now if we were to enter this on the console since isArthur is currently false, we're going to go ahead and get the right side returned from this ternary conditional, the Longsword. Now by itself, this ternary conditional expression will return the right answer but what happened to storing it in weapon which is what happens in our original conditional block? Well we can do that too, let's check it out. So what we've got now is we've got that var weapon declared and we're going to go ahead and assign it immediately upon declaration to the result of the ternary conditional. So after choosing the appropriate sword here, the compiler is going to go ahead and assign that choice immediately to weapon. And if we were to console.log out what the current weapon is, we would see that the current weapon is the Longsword. Cool thing about ternary conditionals is that we can also use them together in concantenation, let's check it out. If we kind of scoot our stuff over here. Get rid of that weapon variable and just place the ternary conditional down in the place of that weapon variable, we can see that, uh-oh, what the heck, man, we got Excalibur out of this. What happened? Hmm, let's see. Problem here is that that cool question mark operator has a lower precedence than the plus concatenation operator, hmm, that's interesting. What does that mean? Well, what happens here is the plus sort of only knows how to evaluate a variable and add it to a string. And that's all going to happen before the question mark actually gets to check any condition at all. So what we got here is current weapon as a string being concatenated with isArthur, the Boolean, before any kind of check happens and that current weapon false is just a string. So now that question mark is looking for a Boolean but it finds a string, so what does it do? Well, it turns out, that in JavaScript, any value will evaluate to truthiness if it not the falsy values. The falsy values are false, zero, undefined, not a number, the empty string, or null. So in this case, the question mark looks at that string and says, "Oh, truthy value, so I'm going to take "the left hand side of our ternary conditional." Well, how the heck can we fix that? Hmm, well, since the ternary conditional can be evaluated as an expression, we can also group it as an expression. So let's throw some parentheses around this guy and you can see now that when we log it out, we get exactly what we wanted, which is an evaluation of the variable only for the ternary conditional check and we get current weapon is the Longsword. So what happens if the king shows up? Well, let's change isArthur to true, which means we've got King Arthur on hand and when we evaluate it you can see we get the current weapon is now Excalibur just as we wanted. Turns out that we can make compound ternary conditions as well. We can use any compound Boolean expression as the condition to check for our ternary conditional. So, let's do that. What we've got here is a variable called isKing and we've set that equal to false. So what that means is we've got some dude named Arthur but he doesn't happen to be the king. Maybe he was named after the king but he's not the king, so he shouldn't get Excalibur, right? So let's see what we can do with that. You can see we put a double ampersand, the double and, right down there next to isArthur and we put isKing next to it to make sure that both of those things are true before we select a condition. Once we've done that, the question mark takes a look at isArthur finds true, takes a look at isKing finds false, though, and so that whole compound conditional evaluates to false and will choose the right hand side of the colon, or the Longsword. Now if we set isKing to true, just to kind of show the other possible result here, we'll get the compound logic evaluating to true on the left hand side of the question mark, which means that the ternary conditional will return just what we expect for the king, which is the sword Excalibur. Something you might see very often out there in the JavaScript wilds is that ternaries can also take action in their results. That means that any executable statement can fall in the left hand side or the right hand side. Meaning when we check the condition, we can actually take action, not just return some value. So, let's take a look. So, we're going to scoot our stuff over here. We got isArthur and isKing moving to the left as our compound conditional check and now on the right hand side of our question mark, we're going to alert, Hail Arthur, King of the Britons, if both of those things on the left hand side of the question mark are true. And if not, then we'll say, Charge on, ye Knight, for the glory of the King. And you can see that since both of our variables are now true. Apparently we've got the king in the house, we get an alert that comes out and says, Hail Arthur, King of the Britons. If we change isKing to false, we got that dude Arthur again, not the king just some random, and we execute the ternary conditional, you can see that we get the correct alert for that situation. Ternaries can offer a concise way of deciding which function to choose on the fly. They provide a slightly different format for picking immediately-invoked functions based on some conditions. Let's check that out. So, we'll scoot our stuff up here and you can see now on the right hand side of our question mark, we're going to put an immediately-invoked function. What's it going to do? It's going to alert, Hail to the king, and it's also going to log out the king's weapon. Following the colon now, we're going to put another immediately-invoked function that's going to alert for the regular knight as well as log out that their weapon is the Longsword. Remember that, if you want to get an immediately-invoked function expression, you will need to add the parentheses behind the expression to call that expression. If we were to evaluate the situation you can see that we would get, charge on, ye Knight, for the glory of the King, since isKing is false, we'll also get a console log out that says the current weapon is Longsword. Now ternaries can also take multiple actions. We want to show you that but we also want to caution you that that can get very dense, so sometimes a conditional block is better for this particular situation but you should know to be very fluent that multiple actions can be taken inside of each result in the ternary conditional. So here you can see after the question mark, we've got a parenthetical expression that has two executable statements in it separated by a comma, so if it's Arthur and it's the king, we want to assign Excalibur as that individual's weapon and Goosewhite as that individual's helmet. On the other side of the colon we've got the same format and we're going to give the regular knight the weapon of Longsword as well as an Iron Helm, for his helmet. So if we were to check out isArthur and isKing, you can see one is true, one is false, so if we were to log out the weapon and the helmet situation, we would see that we would get that the current weapon is the Longsword and the current helmet is the Iron Helm, that's because both of our executable statements in the false part of our conditional, executed. One more thing you might see associated with ternary conditionals, especially under the hood of some JavaScript frameworks, is the nested ternary conditional. A ternary can actually hold other ternaries within each one of the possible responses. You don't want to do this too much because it can get very dense and slightly challenging to read and we always want to be worried about legibility, right? But we want to make sure, again, that you're fluent with this type of code. So we're going to scoot our stuff down and you can see that we have added a variable isArcher and we're going to set that equal to true. Now, in the false portion of our outer most ternary conditional we're going to slap down that isArcher variable as the condition for a new ternary conditional to check, that's right. We're trying to keep this organized, right? And you should too so you want to use indentation as your friend for legibility. Following that isArcher variable, we're going to place another question mark. That means that question mark is looking only at isArcher for a truth value and then we'll build a second nested ternary conditional after that question mark. You can see that if we have an archer, we want to instead assign the weapon to be the Longbow and its helmet to be a Mail Helm. And if it's false, that means we don't have the king and we also don't have an archer, which means that we have just a regular knight and they should get the Longsword and the Iron Helm. Taking a look at our existing Boolean variables, we've got isArthur is true, so apparently it's a guy named Arthur but he's not the king because that's false. He is, however, an archer, hmm. So he is Arthur the archer. Yeah, cool, anyway since we've got Arthur the archer, we're going to go ahead and log out what his weapon and his helmet is and you can see that what happens is since isKing is false, we're going to go ahead and check the second nested ternary conditional. We find that the isArcher variable is actually true and so we assign Longbow as the weapon, Mail Helm as the helmet and if we were to log out his current weapon and his current helmet, we get Longbow and Mail Helm for Arthur the archer.
Logical Assignment I
Welcome back to the sword of syntax, JavaScript best practices. I'm Jason Millhouse, you are extraordinary JavaScript developers getting more extraordinary as the days go by. In this section we'll be talking about logical assignment, a very valuable and often used tool in JavaScript, let's take a look. So all of those logical operators that we used in standard conditional blocks and ternary conditionals, in fact, can make assignments much shorter, even shorter, than ternaries can. Alright, I'm going to establish an armory variable here and we're going to add a property called addSword. That addSword property's going to be a function and it will take in a sword parameter, obviously. Now, take a look at this first cool line of the addSword function. What is this doing? It's kind of spooky. I see this dot swords three times. Well, what it's doing is examining the armory object and seeing if a swords property actually exists and if it does, then what it's going to do is just return that exact same contents of that property to the property itself. That may sound kind of weird but here's what's cool about this ternary conditional. On the right hand side of the colon, meaning if the swords property does not exist, we're going to create a brand new empty array and pass it back to the swords property, thereby creating a new property if it did not exist before. So, in other words, this first line is saying, "Does the swords property exist? "If so, just go with that. "If it doesn't, create a new empty array." That's what this ternary conditional is accomplishing for us. Now your question might be, "How does the ternary conditional know "looking at this dot swords whether that means "there's a property there or not?" Well, remember, that the ternary conditional is just looking for a truthy value and if something is there, that's not undefined, or not a number, or all those falsy values, it will think that there is something true there and go with the true option, very useful. Now here's where the money is in this actual function. Now that we've built a swords property, whether it's the old one or a new empty one, we're just going to push the sword, that's the parameter, into that list of swords that we have built or the one that we had. Now, this section's about logical assignments. So what we're going to do is transform this ternary statement into a logical assignment. Now, this ternary conditional works just fine. It will evaluate whether a property exists and either assign an empty array or go with the preexisting property. But we can eliminate a read of the sword property through a logical assignment, let's take a look. So first we will get rid of the question mark, the condition to check, as well as the colon, and we'll scoot some stuff over here. Now, in between the second this dot swords and the empty array, we'll stick a logical or operator. Now, when used in assignment, the or operator is going to select the very first truthy value that it finds. Can you see how that works? Now, when used in assignment, that or operator that you've seen before, will actually try to select the very first value it finds that's not falsy. In other words, it's looking for the very first truthy value that it can grab onto for the purposes of assignment. So since this may be new for you, let's take a look at what happens if the swords property is empty and does not exist. If I got this dot swords is set equal to either the existing property or the empty array, what will happen when we get to this dot swords it will be undefined, that is falsy. The or operator will ignore it and instead select the empty array, which is not falsy. So what happens as a result? The empty array gets assigned to this dot swords. Now your question might be, "Well, isn't the empty array kind of falsy? "I mean, there's nothing in it." Nope, doesn't care that the array itself is empty because the array is just a data structure, which is not false at all. So what happens if the swords property actually has something, it's actually got some contents? Let's take a look. So, now when I set up my logical assignment, I will get some array that's got some swords in it or the empty array and since the array with some swords in it is truthy instantly to the or operator, it's going to take that and assign it directly back this dot swords. A mistake often made with or logical assignment is that developers sometimes think that both of the contents of the logical assignment get examined, that's not true. Because in this case, as soon as it finds a truthy value, it will instantly make the assignment. That process is called short-circuiting. What does that mean? It means that the empty array in this case will never even get looked at. So, now we're going to take a look and see what happens when we try to use our addSword function with its logical assignment. So we'll scoot our little armory object in here. It's got our addSword function at the bottom right. No swords property yet. So now we call the addSword method using the Broadsword, trying to pass the Broadsword into the list. So our logical assignment triggers. It looks to see if this dot swords is there and it is not. And since it's not, we'll take a brand new, fresh, clean, empty array and pass it to the this dot swords property, which will be created on the fly. Following that, we'll just push the Broadsword to it and you can see that Broadsword gets added to the empty array. Next, to further populate our swords list, we'll try to add the Katana to our swords array. Function gets called, Katana gets passed in. In the logical assignment line, not this dot swords exists. That means that the or operator see this dot swords and says, "Oh, got something that's true. "So I'm going to go ahead and assign that "back to the this dot swords property." You can see that the Katana gets added to the array. And now if we add the Claymore, the same process that occurred for Katana will repeat and we will get the Claymore added to the array. Same thing with a Scimitar because this dot swords exists for each one of those additions. Now, if we were to log out our armory dot swords property, we can see we've got the full array with every last sword that we have added. Something to note here is that the order that we have placed our choices definitely matters, right? We want to make sure that the empty list is only chosen as the very last resort, we always want to go with the existing swords property in this case. So the order definitely matters in your logical assignment. Now to really see that the order does, in fact, matter, let's take a closer look at that or assignment. The or is going to take that leftmost truthy value every time and if none exists, it's always going to be that last falsy value. So let's see what would happen if we switched up the order of the assignment. So, we'll switcheroo here. Put our empty array first and this dot swords last. So what happens now that the empty list is first? Well, when used in assignment, the or operator is going to try to take the very first truthy value that it finds and what is an empty array, all day, every day, forever, it is a truthy value. And so every single time that this logical assignment takes place, we're just going to get that empty array over and over again. Let's see what happens. Well when we try to add the Broadsword this time using the addSword property, yep, we're going to get an empty list. No problem, we're going to get that returned to the this dot swords property and there's our nice, empty array. Then Broadsword gets pushed into that empty array. So everything appears to be working right. Hmm, what's going on? So now what happens when we add the Katana? Well, this logical assignment's always going to short-circuit on that truthy empty array because it's not falsy. So we try to add that Katana and womp, womp. We get an empty list, brand new, and fresh inside of our swords property. We have lost our Broadsword, man, it's like it never happened. Then we push our Katana into that empty array and trudge on to further data destruction because when we continue to add the Claymore and the Scimitar, what would happen? Well, we'd get that empty array destroying our existing sword collection every single time all because that empty array is truthy and short-circuits the check. Then, of course, we log out our armory dot swords and what do we see? Well, one piddly little Scimitar for the entire army. That is bad news for master armorer who now has lost all of his swords, which probably sucks if you're the armorer, so, you know, make sure that you put your default cases at the end of your logical assignments and be very careful to construct them well. To further refine our understanding of this or operation, we're going to look at some other arrangements of truthy and falsy values just to see what they produce. So, here in our first box we've got the variable result1 getting the result of the logical assignment between 42 and undefined. Well 42 will cause that or operation to short-circuit and if we logged it out, we would get 42. Undefined is never examined. Next in result2 we're looking at an array with some strings in it as well as zero on the right hand side. Well, the array full of strings, totally truthy so we're going to go ahead and take that. And the zero is never examined, again, because of the short-circuit. Finally, we got result3 which has an object in it. Object is definitely truthy. On the other side is the empty string. That empty string is never examined for the same reason because of the short-circuiting. So when we log out result3, we're going to get the object. What happens when we switch them up? So in the first one, when undefined is on the left of the or, the or sort of ignores the undefined, can't find a truthy value, let's see what we got on the other side. We got a 42 and so 42 is truthy, we'll pass that back to result1, when we log it out, we see we still get 42. In result2 the array's on the right hand side now and so since zero is falsy, the or will take the array and pass it back to result2. Lastly, the empty string is falsy and so we're going to take that object on the right hand side of the or, which gets logged out. Important thing to remember about or operations, is that the very first non falsy value will be accepted. So your next question may be, "Well, what happens when they're all truthy?" When all elements are truthy, we'll get the very first truthy value found. For example, if we've got both king and Arthur in our logical assignment, we're going to go ahead and take king because that is the first thing, the first truthy value that we find. In result2, if we had Arthur first and king second, we would take Arthur because it's the first truthy value that we find. The moral of this story is that short-circuiting will occur even if both of the values are true. Now the or logical assignment has an interesting behavior when all elements are false. It will examine every possible entry and then take the very last one if nothing is true. So in this case, you see we log out result1. And this logical assignment's way of returning a false value, was taking the very last available entry since nothing else was true. In result2, we put the empty string first and undefined last, you can see result2, however, becomes undefined because that was the last thing, the last resort, that it had to attend to.
Logical Assignment II
So now that we've done kind of a deep dive on the or logical assignment, what about and? What about a double and logical assignment? Totally possible, let's check it out. The and operator's going to find the rightmost truthy value or the very first falsy value. Sort of the opposite that the or does. If you look at this and logical assignment for result1, you'll see that it takes undefined as an answer because as soon as it has found a falsy value, it short-circuits knowing that there is no need to check any further values because it's already found something that's going to cause the whole compound to be false. In other words, 42 is never even examined. In result2, you can see that the zero is the first falsy value attained and since now we can't make a truth value out of that compound, we're just going to take that zero and assign it back to result2. In result3, we've got the empty string first. No matter that there's an object next, we're just going to take that empty string because we obviously can't complete the true value. If we switch it up, we find that we get the same exact results because the compiler is seeking to find only truthy values and when it finds that something is false at any point, it will assign that false value right back to the variable. When all of the elements are truthy, and will return the very last truthy value found for assignment which is what makes it often very useful and very functional in code. So let's take a look at this first one here. On result1, since king is truthy and Arthur is truthy, what the variable will receive is actually Arthur. We've examined the king, found that it's cool, we move over to Arthur, it's also cool, let's pass that back to the variable. Notice if I switch them up in result2 and got Arthur first and king second, king gets returned after a full examination. Just to kind of compare that with or, we had this a little bit earlier, you can see that in the or situation with king and Arthur, we get king because it is the first truthy value. I didn't need to look at everything, so I just took the first one I could get. In result2, I take Arthur for the same exact reason. What happens when they're falsy? What happens when both elements of an and operation are falsy? You can see in result1 and result2 that we short-circuited on undefined and the empty string, respectively, because there's no need to check for any further truth values when we've already found a false. Let's contrast that with the or situation, which needs to look through all of its entries before finally returning a false value if that's all that was there. So inside result1 and result2, we get the empty string for result1 and undefined for result2. Now where might you use this and logical operator? It's very useful in contingent assignments where one thing's got to be true before this next thing can happen. The and operator's going to check as well, multiple conditions, before we actually allow that assignment. So, let's take a look. Here we're going to add some functionality to our armory object. Namely it's going to be called a retrieveSword property that will hold a function. The parameter for that function will be a request. That means which sword we would like to get, or check out, of the armory. And we've got an interesting expression here. We're going to return the result at a ternary conditional. Now, let's check out how we're generating the condition for this ternary conditional. What we're doing here is actually checking to see first whether the swords array actually holds the sword that we want. So, how do we do that? We use the index of method which is a method of array prototype that will examine an entire array and return the very first found index for any matching value and if it doesn't find anything throughout the entire array, it will return a negative one, which may now be very clear to you why we use a greater than or equal to zero inside of our check. If the index of method returns a value that's positive, that means that our sword that we want is somewhere inside of our big, long swords array, right. But if we get a negative one, that means the sword is nowhere to be found and our ternary conditional should return the false value. So just the illustrate the power of this index of method for a moment. Let's pass Claymore into the index of method on the swords array. What it's going to do is look through that array over there in the armory. You can see that the Claymore exists in index two, remember the arrays are zero based, and it will return that two. So that we know that the Claymore is exactly in index two. However, if we go hunting in the swords list for a donut, that's going to return negative one because hopefully there is no donut in the swords array. Fight with donuts. Now that you can kind of see how that index of method works, notice that our check in our ternary conditional is looking for a number that is greater or equal to zero. That means we want to verify something actually exists in the swords array. If it doesn't, it should be a negative number. Now the left side of our ternary conditional colon, if in fact the sword does exist, we're going to use some index cleverness to remove the sword from the swords array. Let's see how we can do that. We'll use the splice method. Now that's going to remove elements anywhere inside an array by first passing in the index that you want to start at and following that with how many items you want to remove at that index. Let's just take a look for a second. If we create a soldiers array. We got Knights, we got Pike men, we got Archers, and we splice that array at index one for two units. Now what does the splice method do here? Well, it's going to go into index one, which is Pike men, it's going to take out two entries, including Pike men and Archers. And what does the splice method return? It returns those values that it spliced out inside of their own, brand new, array. So how can we use this cool splice method to help us remove gently our sword from the swords array? Well you can see inside the splice method, that we pass in the index of our requested sword using the index of method. Following that, you see that one right there? That's saying, "Go to the index where the sword is "and just take out one sword, "that's all we want is one sword." Now, since the splice method returns an array but we only want the string of the sword, we will need to access the zeroth index of the array that gets returned. That's what that little bracketed zero is doing there. It's going to return us the single string from inside the returned array of the splice method. Yay, for code. And then after the colon, you know, if we never found that sword originally when we went to check for it, we need to go ahead and say, "Yo, man, that sword ain't here." And that's going to be useful when we actually employ our double and assignment. So now let's go ahead and try to use our retrieveSword method that we've added to the armory. We're going to set up a variable called isKnight here and we're going to set it equal to true. We only want knights, you know, to be able to get swords out of the armory, we don't want serial killers running around with weapons from the armory, that could reflect poorly and suck moderately so let's not do that. The next thing we'll do is have a variable called weapon and we're going to set up our very cool and logical assignment. The very first thing that that and will check is whether the person that's asking for a sword is a knight. Well, isKnight is currently true so and here is going to keep checking and what is it checking on the other side of the and? It's a call to a function. Okay, so let's see what happens here. If the result of our retrieveSword function happens to be a string, well, a string is truthy, right? So we'll get precisely the sword we're looking for because, remember, that and returns the final truthy value that it encounters. Cool, so let's see what happens when we try to get this Katana assigned to the weapon variable. First, is there even a Katana in the swords array? Our index of method goes over the swords property, checks the array, finds a Katana, ding. Returns index one and since that is greater than zero, we get a truth value in our condition and the ternary will execute the splice method on the left hand side of our colon. So, now let's see what happens when we try to get the Katana out of the swords array and pass it into the weapon variable. So, we're going to splice that swords array exactly at Katana, and that's going to hand us back another array, and from that array, we're going to take the string at the zeroth index. This will also remove the Katana from swords. So, now that retrieveSword has passed back a string Katana which is truthy, and also isKnight has a truthy value, both of those things are truthy so we will take the last, the right hand side of the and logical statement and put that inside the weapon variable. Check it out, when we log out that weapon, we see Katana, woo-hoo. Cool, so we got the Katana out. What happens if we try to get a Rapier out of the swords array? Well, we pass in Rapier into the function, and the index of goes over to the array, and checks and sees, womp, womp. There is no Rapier in the array. We need to make a purchase order, I guess, or something. But it's not there now. So what's going to happen is that condition will be false and on the right hand side of the colon, we will choose the alert method and once that alert message is called, you can see we get our popup box, but what happens to retrieveSword? What happens when the very last thing it has done is call an alert method? Well, it happens to be that it returns an undefined value. So, since that undefined value is the very last thing our and value finds and it's falsy, it's going to toss that undefined value over into weapon and weapon will be undefined. There will be no weapon in sight. Now, you might ask what happens when isKnight is false, I mean, we don't want some random dude coming up to the armory and requesting a weapon, right? So, if it's false, turns out retrieveSword will never even get called. Remember, because and logical assignment will take the very first falsy value it ever finds. So, since isKnight is false, that false is going to get tossed over into the weapon variable. If we log out the weapon variable, we can see that this becomes false. An extra bit here, logical assignments are actually extendable. You can string together as many operators as is necessary to choose whatever right assignment you would like to. So, let's scoot our stuff down here and you can see that we've got a new variable called armoryIsOpen and we're going to set that equal to true. Inside of our and logical assignment, we're going to add that armoryIsOpen variable as a new condition. This is an extended logical assignment. So, now if the armory is open, which it is, and the person is a knight, which they currently are, and if there's a Claymore in the array for the swords, and that gets returned, then we'll take that sword, and assign it to the weapon variable. That happens here, so you can see when we log out the weapon, we get the Claymore. So what happens when the armory is closed? It's not open, well, we don't want to be passing swords out after hours, right? So the double and, that first double and, will see that armoryIsOpen is false and that will instantly get assigned to the variable weapon with a short-circuit not looking at any of the other stuff that's present in our extended assignment. You can see that when we log out the weapon this time, we get false because the armory was not open.
The Switch Block
Hey, guys, welcome back. Hope you enjoyed that set of challenges on logical assignment and now we'll be moving into the switch block, let's take a look. You can think of the switch block as kind of a conditional for multiple possibilities. JavaScript has sort of an alternate way of taking action based on values instead of just Booleans. So here we have eight different regiments. And each of those regiments is supposed to get a different weapon. Each of those knights in those regiments need to hold on to some different killing device. Let's say we had a knight constructor, and inside that knight constructor we were passed a name and a regiment, in order to assign that new knight to a specific regiment and give them a name. Then, we have this extra long series of conditional statements to check and see what the regiment value is, in order to assign that knight the correct weapon. So, if we made a new soldier variable, and we assigned it a knight from the constructor, we would pass in, let's say, Timothy, and he should be assigned to regiment two. When we logged out this soldier's weapon, you can see that we would get the Claymore but in this code, it's kind of tedious, right, to type all this out, where you're repeatedly using if and else and the processor has to repeatedly check the regiment value over and over again. We can use instead a cool JavaScript keyword that will jump directly to the right action to take. This switch keyword will allow us to assign a weapon based on a value itself but without the Boolean check. First thing you need to do is place down the switch keyword, then a set of parentheses, which contains the value you want to switch upon. It signals to the compiler to take some specific action based on the value here of regiment. Now, the switch block is going to contain multiple cases, and each one of those cases is going to be followed by one of the possible or desired values of the switched upon value. In this case, regiment. Following that value, you see a colon, that separates the case and its value from the action to take. We're going to go ahead and fill in every single case here for our knight constructor, you can see each weapon is associated with a different regiment value. So, now we feel pretty good about our switch block, right? So, let's see what happens when we create a new soldier2 variable and assign to it a new knight from the constructor. It's going to be Richard and his regiment is going to be four. Now, let's log out his weapon and we get, oh man, a Morning Star, what happened? What is wrong with our switch block? Something that happens quite frequently. Let's take a look. You can see in case four, Richard should've got a Mace, right? But he actually got the Morning Star, which is in case eight. Something unique happened inside of our switch block. The thing about JavaScript cases inside of a switch block is that they allow fall-through to other cases. You have to think of the case keyword and its value as sort of this label that identifies the starting port for execution for the rest of the block. Now, that fall-through is sort of a vestige from the very common C language around which JavaScript is loosely based and has a relationship. It came about for two primary reasons. One, people wanted to be able to execute more than one case at a time within a single switch block as well as the fact that they wanted to be able to have multiple case values take the same action. So, we'll look at both of those useful situations in a bit but for right now, let's take a look at this block and see what we can do to fix it. Now, as we said, once a case label has been selected by the switch block, all of the other labels that are inside that switch block are completely ignored because the switch jump on the value has already occurred. What that means for Richard is when his number four gets passed in right now, the switch block jumps to case four and assigns him the weapon Mace but then, the case five label is completely ignored and so he gets assigned War Hammer. Then he falls through to case six and gets assigned the Battle Axe. Then to seven, gets the Halberd. Then to eight and, finally, gets the Morning Star. So fall-through can be a little dangerous and we need a way to fix it. And what will fix it, the break keyword. The JavaScript break keyword provides a very quick exit from the switch block, and any block. Break will allows us to leave an entire block of code that contains it. In this case, we're going to use it for the switch. So, let's space out our constructor here. We're going to shift things around and give ourselves a little bit more space and inside each case, we're going to place a break keyword. Now, when we try to build our knight object for Richard, and we pass in his regiment four, we're going to jump all the way down to case four, give him a Mace and break instantly out of the switch block. Since that was the only case that was taken, when we log out Richard's weapon, we get the Mace. As we expected, woo-hoo. And we want to back up for a second because fall-through kind of gets a bad rap a little bit out there in the wild but it can be very useful and we want to educate you on the uses of fall-through. What if multiple cases, for example, take exactly the same action? We can creatively use fall-through to make that happen and tighten up our code and make it more legible. Let's take a look at regiment seven. What if we didn't want regiment seven to use the Halberd and where we wanted them to use the Morning Star? Well, what we could do is completely remove all of the contents for case seven, including the break keyword, and stack it, that case label, on top of the case label for case eight. By doing this, we've associated all of this subsequent actions with each of those cases. Now, you might ask, "Well, what if I wanted to move "one of those earlier cases, say, "a regiment four, who currently uses the Mace, "what if I wanted to make regiment four "use a Morning Star as well?" Well, JavaScript doesn't care about your case order so you can move around your numerical cases and place them wherever you'd like. Additionally, you can stack as many cases as you'd like on any particular set of actions. Fall-through can often be useful if organized well. So, how does that affect Richard? Well, if we made our new knight object using Richard and his regiment number four, now you can see, that he does, in fact, get the Morning Star because of that useful fall-through we placed in our switch block. Earlier, you may have been asking yourselves, "What happens when the switch block "gets a value that's not actually present "as a case inside of the block?" Well, we have a unique situation for that. If a case value doesn't happen to be there in the switch block, no action at all will trigger. So, if suddenly we passed in Arthur and he's the king, well, there's no king regiment, right? So, his weapon at the end of that object build, would be undefined. That's because the weapon property is never actually set to a value. So, we can fix that by adding another case. Notice, here, that this case for the king uses a string and that's because a string is a perfectly acceptable case label. In fact, JavaScript will accept any value that happens to be matchable with what's passed into its parameter. Now, when we call our new knight constructor, and it happens to be Arthur and he's the king, we assign that result to the king variable and we log out the king's weapon, we get Excalibur as we would expect. What happens if we've got a knight but he gets assigned some regiment number that doesn't exist? Well, he's not going to get a weapon, right? And a knight that has no weapon sure sucks a lot. So, let's see what we can do about that. JavaScript offers this default case to help us watch for unavailable values and do something specific when an unavailable value is encountered. We label a case with default and inside there, what we're going to do is just alert the armorer that this dude we're trying to make a knight object for has apparently an incorrect regiment and we will not assign him a weapon. So that the armorer can make sure that we get him into a regiment, where the right regiment number exists. So, now if we try to make a new knight object for this guy, Jerome, and we try to pass in regiment 12, which there is none, the default case is going to be taken by the switch block and the armorer will get a nice alert that says, yo man, I fixed Jerome, because that guy ain't got a regiment yet. You may notice on our default case, that there is no break statement. What about that final break statement? Well, you know, since no other case exists after our last one, there will be no other executable code inside of the switch block. So that last break statement is optional. A second usage of JavaScript fall-through that must be tightly controlled but can still be very useful, is that of hierarchical code execution. If you have a very carefully organized block, you can make all of least common properties be added first and all of the most common properties be added last through the switch block. Let's take a look. Here we have a ceremonialDagger constructor and that ceremonial dagger is going to be passed to each knight upon their knighthood depending on their particular rank. Here you can see that the length of the dagger is set to eight and the owner is set to whichever knight is passed in to the constructor. Now, the quality of the ceremonial dagger will built based on the rank of the knight. So, you can look at the bottom of our switch block here. You can see that we're giving the lowest level, which is just a regular knight, we're giving that knight six rubies on their ceremonial dagger. Now, the next rank up is going to be the captain of a regiment. Now, the captain of a regiment should have something special on their ceremonial dagger. You can see that our captain gets exactly one emerald. Now, notice, there's a fall-through here, meaning that the captain will not only receive one emerald, but since there's no break statement, they will also receive all of the rubies that a knight gets because of the hierarchy we've arranged our code in. The next highest level is the field marshal. This guy's going to get four sapphires. If you are a field marshal, you are sitting pretty. Not only do you get four sapphires, but you get also the one emerald of the captain, and the six rubies of the knight. Above all of the field marshals is the single high constable and this guy gets two amethysts on his ceremonial dagger, in addition to the four sapphires of the field marshal, the one emerald of the captain, and the six rubies of the standard knight. And if you are the king, the man, the myth, the legend, King Arthur yourself, then you're going to get one diamond exactly in the pummel of your ceremonial dagger. Not only will you get that diamond, but you will get every other gem assigned to every other level of military officer. So, now let's make a new ceremonial dagger for Jerome, who is just a standard knight. Now, what happens when we call this constructor, it's going to jump straight to the correct case, with no fall-through at all before or after, thus, all we're going to get is six rubies and no other gemstones. If we log out that knight's dagger object now, we can see that the length is eight, the owner is Jerome, and he has only six rubies. If I make a ceremonial dagger for Timothy, who happens to be a field marshal, and we assign that to the variable marshalsDagger, then what happens is the constructor gets the four sapphires for the field marshal, the one emerald for the captain, and the six rubies for the knight. And if we were to log out the marshal's dagger, you can see that we would have a length of eight, the owner's Timothy, and we got four sapphires, one emerald, and six rubies. Fall-through allows that field marshal to acquire the lower ranked gems. Last but certainly not least, you can see that if we make the king's dagger, for the man and the myth, we will get a diamond, two amethysts, four sapphires, one emerald, and six rubies for His Majesty. Used in careful, controlled hierarchy, fall-through can be very valuable but you have to keep a close watch on it to make sure that the hierarchy stays stable during the maintenance period of your code.
The Pendant of Performance
Loop Optimization
Find the Sword of Syntax first For the useful tools that you may need Wear the Pendant of Performance For efficiency and speed Caution's Crystal clears the sky With triple equals and try-catch Avoiding stuff that sucks and parsing Pattern numbers out of stretch Alas, the golden shining mail of modularity When namespace closure imports long Defend integrity For polished jewels and JavaScript the treasure trove this is Now raise your sword and strike your shield With these Best Practices In this level, we'll be looking at speed, how to improve it and how to measure it. Many new developers think that the only way to improve performance is through complex algorithms that manage data more efficiently on the server side, or through a generalized improvement to the bandwidth of the user's internet connection. But there are subtle and often overlooked methods in the JavaScript language that you can begin to incorporate immediately, and that on a broader level will have a noticeable impact to the speed of your web applications. Additionally, often it's very important, especially in this day and age, to test multiple implementations that produce the same result, in order to make the best decision about which implementation provides the best user and developer experience. To that end we'll examine ways to illustrate that speed and time data so that you can make the best choice about which implementation is best for the task at hand. And with that I hope you enjoy and hold carefully to the Pendant of Performance. Welcome back, this is level two of JavaScript Best Practices. I'm Jason Millhouse and this section is about loop optimization. Let's take a look at a common for-loop scenario where memory access may not necessarily be ideal. The first thing we'll have here on the right is a treasureChest object. Inside that object we'll have 10,000 gold coins. We'll have the Crown of Speed as a magical item. We'll have an array of necklaces. And we'll also have a function called openLid. Now, if you want me to log out all of the necklaces found in our treasure chest, we would have a little log here that says "You've found the following necklaces." Following that we could do a loop. We've set up our loop parameters in a normal fashion where we loop over the entire length of the necklaces array and log out each one of the necklaces in that array in turn. That would produce "You've found "the following necklaces: "ruby, pearl, sapphire and diamond." And this is not the best way to execute loop control because at the start of each potential loop cycle, the program is going to need to find and retrieve several things. First, it will need to find the value of i. Then it will need to locate the treasureChest object, within which it will need to find the necklaces property. After finding the property it will need to reference the array pointed to by the property. And then, finally, the length, because that's what we need. So out of all those steps which ones can we actually eliminate safely? Because any intermediary step to finding what we want is just lengthier processor death time. So we want to make sure that we can get rid of as much steps as we can. All we're interested in during loop control is that single length value and the loop counter. So we don't really need all of these other little steps that we take to find that length value. If we use cached values to curtail all of that lengthy, repetitive access, you'll find that your applications improve in speed. What we'll do is we'll our stuff down here and we will assign the length of the necklaces array to this new variable called x. This will use all of the accesses that we had before, all of those steps, but it's only going to happen once. Now, inside of our loop we'll use that x variable as the controlling parameter. As a result, the majority of all those extraneous steps have now been eliminated. Every time you help your processor out with some savings that's going to mean more speed, and so let's check out and see what we've actually saved on our moderately simple example. So now during loop control memory access only needs to retrieve the value of i and then retrieve the value of x. Then, we do need to add in our one-time cost in creating our new x variable. What does that mean? That means we created the variable x in memory as a step, and then there're also the four steps that we saw before in actually retrieving the length value from the array inside the object. Now, if you can tolerate a little math here, we've got two steps for every loop. That means that we're going to do four executed loops and then a single check to stop, so that's five total starts of the loop parameter. So two times five is 10 steps for the processor, just in memory access. Then we'll add in those five extra steps in the creation of that extra x variable. So a total of 15 steps of strictly memory access to execute just one loop. Seems pretty good. Let's check out the difference. In our previous version we took 25 steps to figure that out. So the difference of course is 10 steps of savings. Now, that may not seem like a lot, but let's check out what happens when we grow our data considerably. What if we had 10,000 necklaces? With large data amounts, this improvement is really going to improve results. You can see that when we have five steps times 10,000 executed loops plus one check to stop, we get 50,000 memory access steps. Oh my god! But when we have two steps times 10,000 executed loops and one check to stop, we only have 20,000. Then we add in five extra steps to create that x variable, see how that doesn't matter very much, and we get 20,007 memory access steps. Now, what's the difference there? 30,000 steps of savings. You can see how you're assisting the processor quite a bit by caching values. So we've saved all of those steps, really cool, but we can be even better organized if we place that control variable that we've created inside the parameters of the loop. Let's take a look. First, we'll scoot our treasureChest down here and we'll give ourselves a little bit more space inside of our loop parameters and surprise, a comma is going to allow us to execute multiple statements within that very first parameter of our loop. Now what we can do is scoot our variable over and bring it down into the first parameter of the loop. A cool thing here is that we can now get rid of this var that's on the outside of the x. It's now unnecessary, because that comma is going to tell the compiler that more variables are about to be declared and maybe even assigned. By creating both of these variables in the loop parameter, we now have signal that they're actually only intended for use inside this loop. We've also limited the processor burden of declaring multiple variables with that var keyword. Something to take note of here is that JavaScript doesn't have any natural garbage collection. That's right. If we were to check this our, log out the x variable after our loop, we get a four, and that's because JavaScript does not scope to blocks. So any of the variables that you declare inside your loops, they're going to be available after the loop, uh-uh, weird, and they may actually overwrite pre-existing globals. So you have to name your variables very carefully. You may have noticed that a good approach to take when dealing with this kind of repetitive data access at depth is to store in a local variable any property, or object, or array item that is used more than once inside of a function. So the moral of this story is try to avoid that repetitive, repetitive, repetitive access at depth. And in our current code we can even find a new place to further streamline this process. Let's take a look. See that console.log in there with treasureChest.necklaces? That's another access of a property within an object, and we're going to do that every single time. Looks like in the loop, right? So we want to try to avoid that repetitive access. Let's see what we can do. So we'll make a new variable and we'll call it list and it's going to be the array of necklaces, and we'll just assume that this list variable is going to get used some place later in our code that we don't see yet. But by creating that list variable we now can use it inside of our log without accessing the treasureChest object. You can see if we drop that list variable down and scoot it over, we will be logging out the ith index of the list variable. And we've avoided that extra step of accessing the treasureChest each time. On a broader level, there're other ways to optimize the loops that are inside your code, and one way is to make sure that you're choosing the best kind of loop for arrays. If you want to just deal with each index inside the array, your best bet is to stick with for-loops instead of for-in loops. To see why the regular for-loop is often better for performance, let's go ahead and add a few methods to the array prototype. Here we go. Here we have a new method on the array prototype called countType, and you don't really care what it does or what the code is inside this function. You just need to know that it would now be available to all arrays inside of our program, including that necklace array over inside the treasureChest. We'll scoot that down and we'll also add another prototype method called removeAll. You don't care what it does but you can check it out later if you'd like. Just know that it's another array method that we have added to the array prototype. So now that we have added a couple methods to our array prototype, let's see what happens when we change this existing loop structure that lists all the necklaces to one that uses instead a for-in approach. You will see in a moment why this kind of sucks and it's going to impact the performance of your code. So, we get rid of all of our loop parameters here and in their place we put for p in list. That means for every property inside the list. And that is going to come in very key in a second. If we were to now run this code and we would see the results of our console log, we would see "You've found the following necklaces: "ruby, pearl, sapphire, diamond, "removeAll, countType." I don't want the removeAll necklace and I also don't want to wear a countType necklace. But the reason this is happening is because using a property approach to access indices is going to result in adding in all the methods that have been added to the array prototype. So if there's ever any additional methods on the array prototype those are going to be included inside of your properties. Very strange if you only were concerned about the indices of your array, right? The reason that is because methods that you're going to add to the prototype, not the existing methods, but the ones that you will add to the prototype, are going to become enumerable just like the indices in the array. Now the moral of the story is that you really should only use a property approach when you really want to get to every single property of that array. Otherwise stick with the for-loop and you will have exactly the functionality that you desire.
Script Execution
Hey, guys! Welcome back. This is section two of The Pendant of Performance, and in this section we'll be talking about script execution. Script placement inside of your HTML files very much impacts performance. So let's take a closer look at how a browser actually retrieves and acts on the scripts that you place inside your HTML. When a browser tries to access a page, it's first going to send a request to the server for the document contained at whatever URL you're trying to get to. The server of course is going to find that document, hopefully, and pass it back to the browser. Then the browser begins to parse the document and that's where things can get a little bit crazy on the performance side. The document could need any variety of important things that make a website, you know, awesome, such as CSS style sheets, images, tons of images actually, and of course scripts. Under normal circumstances a modern browser is going to be able to download up to six components at the same time in what's called a parallel download. But when the browser finds a script to download on the page's code, all that parallel downloading halts, that's right, stops until the script is finished loading. This can mean super slow load times for your site sometimes. Where would we find such troubling scripts that have some sort of adverse impact on our performance? Any scripts that are high in the head or the body tags of your HTML page can potentially have a performance impact, if they're not absolutely necessary and even if they're absolutely necessary. So let's take a look at this website here. We've got The Third Regiment's page and right after that first heading you can see that script tag that looks for sparring.js inside of The Third Regiment's website. That seems harmless enough, right? We'll just get a quick download of it, and then we'll just get on with our lives. It'll be great. But what happens if that sparring.js file is processing tons of really time-consuming data intensive problems, in order perhaps to make use of a bunch of data that's on the website? For example, it could be building a huge array of soldiers from some separate file. It could be calculating all of the possible unique groups for sparring groups of two, sparring groups of three, sparring groups of four out of all the knights. Pooh, that's forever. Randomizes the order of those sparring groups, if they're having some sparring day. Collects groups in pairs in order to have larger matches for whatever reason. And more processes, more processes, more processes, it goes on forever, right? While that script file is handling all of those data intensive processes, everything after that script file, namely the rest of your HTML page is going to stare at you. It's going to hang and it's going to wait for all of that to be done. The result, of course, is poor load time and probably poor user experience. We want to avoid that and figure out some ways that we can afford it. Let's check it out. One great solution is to relocate all of those work-intensive scripts, because any script that's not really essential to the immediate loading and presentation of your webpage should be moved as low as possible in your parsing of your HTML page, so that that page can be present for the user immediately. Let's check it out. So what we'll do is we'll push up that paragraph to be right after the first heading and we'll move the script down right before the end of the body tag, which is a great place for work-intensive scripts. Now, most of the visual information, all the other components of the site, that's going to become available for the user to check out while the data is being processed. Very valuable. A second short solution for this kind of problem is to use the HTML5 async attribute inside of your script tag, which will allow the rest of the page to load before the script actually runs. So let's examine that one, too. So we'll push up paragraph back down and we'll move our script back to its original location. Now what we're going to do is we're going to add an async attribute inside that tag, and that's going to prevent the script from blocking the page's load for the rest of the page. Now, we've got that async attribute dropped in there, but even though it's in the back here, you can put that async attribute as an attribute any place that you want inside your script tag. So what's going to happen now? Well, the browser is going to parse all of that initial HTML, and it's going to reach the script tag, and it's going to say, "Let's go get that script file." And then it runs to get the script file, but then sees the async tag and says, "Well, we need to load this script file "at the same time as the rest of the HTML "to be parsed on this page." This allows the rest of the document to get parsed, loaded and ready for the user while any contents of the script file are being processed in the background. So async will give us much less of a processing time delay hit and can allow scripts that need to be high in the page to avoid hurting initial load time too much.
Short Performance Tips
Hey, guys! Welcome back. This is section three of The Pendant of Performance. The section's called Short Performance Tips, which means that we're going to be giving you a few easy implementation switches that will affect your performance positively. Let's take a look. The first thing we want to give you is this idea that inheritance can help your memory efficiency. You want to be aware of taking single objects and loading them up with repetitive code that could be sourced and held somewhere else, ideally a prototype. Taking a look here, we've got the signal fire constructor. That's right, we're going to be building some signal fires. You can see that it takes an id for the signal fire, as well as a certain amount of starting logs that the fire gets. Additionally, you can see there are three other methods that are added in here, addLogs, lightFire and smokeSignal, which have all sorts of unique functionality for the signal fire. Now the thing about those three functions is that we don't need to build all of those methods within every single SignalFire object because we're going to use extra memory to store that functionality with every object, and it would also take longer to create when we're calling the constructor. So, if we had this world spanning signal fire system with multiple fire objects, we'd have to replicate all of their functionality with each one of those signal fire data structures, which would suck. So let's take a look at a way we can improve that memory efficiency using inheritance. The way that we can avoid all of that repetitive memory usage is by using a prototype for all of our shared stuff. We want to give the common methods that each one of these objects will share, we want to give that to a prototype and then just have all the objects inherit from the prototype. Let's check that out. So we'll scoot down our smokeSignal function here, and then we'll scoot over our addLogs and lightFire methods. Then we'll get rid of these equal signs and replace them with colons. And then we'll wrap the whole deal in the SignalFire prototype. And now all of these methods can be inherited by every SignalFire object. So now, if we have fireOne, fireTwo and fireThree created through new constructions of SignalFires, you can see they all start with an id as well as many startingLogs as they have each. And then if we were to call addLogs on each one of those SignalFire objects, each of those SignalFires would be accessing the method contained only in the prototype object for the SignalFire. Additionally, if fireThree saw some goblins and needed to alert their nearest neighbor, we could send a smokeSignal on goblins, and we would get G-O-B-L-I-N-S, exclamation point, because goblins are serious. Moral of this short story. Make sure that you add all common functionality to a prototype so that every single data structure that's inside of a class of objects doesn't contain that shared functionality itself. The next short performance tip that we want to give you is that adding individual DOM elements to the DOM is not always your safest fastest friend. We want to make sure that you know that each new addition to the DOM is going to cause a document reflow. Ugh, that's terrible and can very often hinder user experience. Take a look at this website over here on the right. It's the Knights of the Week site apparently and we have an unordered list on it there with an id of kotwList. Later one, there's a script tag that calls the kotw.js file to be loaded. Let's take a look at that file. Inside there we grab that unordered list element and assign it to the variable list, and now we've got this list of the Knights of the Week. There they are: Jenna Rangespike, Neric Farthing and Darkin Stonefield. Next we've got a for-loop that loops over all the knights of the week and first, for each element creates a list item element, and then adds a text node with that particular knight's name to that element, and then adds the element itself to the unordered list element inside the HTML page. Each time that list is appended, you're going to access the DOM and you're going to cause an entire document reflow. That's not as speedy as we'd like it to be, especially if our list was 4,000 knights assigned to this regiment for printout, that would suck. So we don't really want that to happen. Let's take a look at a way to speed that up. Cool thing about HTML is the document fragment, which can be used to insert a whole bunch of conjoined additions all at once instead of in pieces. Fragments are like invisible containers that hold multiple DOM elements without actually being a node itself. They're very cool. Let's take a look how to use it. So what we're going to do is we're going to create an extra variable here called fragment and then we're going to use the .createDocumenFragment method to assign a new fragment to that variable. What that fragment is going to be is sort of a staging area. It's going to hold all of our new li elements for our page. On the inside of our loop, instead of adding our created element with the knight's name as a text node to the actual unordered list element, I can't do that anymore, we're going to now put that element inside the fragment as a staging area. Now we'll need to add another line right after our loop that will finally add the fragment that contains all of our elements to the document. Notice that this is happening in one fell swoop, we're only touching the DOM one time in order to add all of those elements to the unordered list. We're going to give you a little bit of a side bonus best practice here. We want to make sure that you declare variables as few times as possible. That's because every time you use one of those var keywords, it's going to add an extra look-up for the JavaScript parser and that can be avoided with those comma extensions that we saw in the first section of this level. Let's take a look. Alright, so we've got already vars on list kotw and fragment, and if we take the vars off of kotw and fragment, we can put commas. Comma behind the list variable as well as behind the kotw variable. That will show that we're declaring multiple variables in a row, just as we did in that looped optimization segment. Using these commas is really great for eligibility for when other developers are looking through your code, they can see that you've got a nice list of variables stacked using commas. Because of that processor burden you want to avoid declaring in loops. You want to try to anticipate your variable needs so that you're not causing the parser to look that variable keyword up over and over again, right? Let's take a look at that. Here you can see our var element and that variable's going to be declared every single time our loop executes. That means we're going to need to look up what the var keyword means every time we want to declare that element. Some will argue that declaring variables right when they're needed is very useful because it tightens the understanding of your code so that people can see that you've declared this variable right where you have needed it. But you want kind of weigh that with the trade-off of the processor burden. Since our script here is sort of very small, we are going to go ahead and declare that element outside of our loop and then use the element inside the loop. So first thing we'll do is we'll get rid of the var on that element inside the loop, and then we will add the element to the list of the variables outside the loop. That's a great trade-off, because we've got such a short script. We've opted to avoid processor burden instead of having the element declared exactly where it is used. The goal here is to make sure that you anticipate which variables you'll need ahead of time so that when you encounter loop environments in your code, you won't need to re-declare those variables over and over again. The last little performance tip we want to give you in this section is that we should always make efficient choices when we are trying to figure out how to concatenate a set of strings that we have. In building strings, there're several different methods that will yield uniquely different results in terms of execution speed. So let's take a look at that. Here we've got three new variables, knight, action and weapon, each with a string inside it. Next we'll have a variable called turn, and what we're going to do is concatenate all three of those variables together to create Jenna Rangespike's turn. Here the standard concatenation operator has been optimized in most browser versions. That's an ideal choice if you are using a small number of string concatenations. But one more time, the concatenation operator will probably be your best bet if you have just a small amount of strings to concatenate. However, if we had a variable that consisted of an array of multiple hundreds of HTML elements, for example, if we were pulling HTML elements together to build a new page, we may want to loop over that array in order to put all of those elements together. So here you can see we've got a page variable, starting out at the empty string, and then we loop over all of those array elements forever concatenating. And that's going to get the job done, but there is another method that will enjoy a performance boost specifically when your strings are inside of an array. You always want to decide what's better before reaching specifically for the concatenation operator. When you are trying to concatenate the strings that are inside an array's contents, instead use the native join method on arrays. That's going to be inherited from the array prototype. Here you can see us use the join method on the newPageBuild variable, and what that's going to do is concatenate each index of our newPageBuild array, and those indices are going to be joined by any string that you pass into the join method. Here you can see we've got the new line going in there, so as to put a new line between each element of our newPageBuild long string. When your strings are in an array, this method is going to be extremely faster than using that concatenation operator over and over again in most of the tests that we've designed for it. Also, it's a little bit easier to read because a developer can understand exactly what you're doing rather than trying to figure out what your loop is trying to accomplish. Now that we have joined all the elements of our array using new lines and put that into our page variable, if we were to log that page out now you can see that our HTML page is grouped very nicely with new lines in-between as one long string. Super cool.
Measuring Performance I
Hey, guys! Welcome back. This is section four of The Pendant of Performance. In this section we'll be examining how to test the speed of your code. Very often it's very valuable to test your current implementation with other potential implementations in order to see which provides the best performance and therefore, the best user experience. So let's build a little code and then test its speed. Here we go. So remember that knight constructor that we used in level one? We're going to use that again. So let's get it up here and we're going to move it down to the side. We're going to examine a very simple console method that will access the time any code we build is going to run. Let's see how it works. So we've got a variable here called firstRegimentNewbs, and that's an array of all of these guys that are about to become knights but they are newbies, Grimble, Jark and Bunder. And then the very next variable we have as the master list of all of the first regiment Knight objects, in which there're tons of Knight objects. Next we've got a loop that loops over all of the newbies, creates a new Knight object with that newbie and the regiment number, and pushes the new Knight object to the list of existing knights. This is the code we're going to test for time. We're going to scoot go down our loop here, and right before our loop we're going to put console.time. Yes, the console.time method will take any string and will start a timer with it. You can see here that we've got time to add, and then a certain amount, and then knights. So it's going to say "Time to add three knights" in this case, because firstRegimentNewbs has three knights in it. Following the loop we're going to use console.timeEnd passing in the exact same string, which is key, in order to cause the timer to stop and close up. If we were to run this code now, which we did on our browser, we got the time to add the three knights was 0.036 milliseconds. Not very much time, right? console.time will automatically preface the time measurement that it finds with the string that you passed in as a parameter, and it will follow that string automatically with a colon to separate the numerical portion from your label. Just to show that it would take a little bit longer time if we added a newbie to the firstRegimentNewbs array, we're going to add Ernst Breadbaker over here on the back end of that array. And now when we run this code, you're going to see that the time to add four knights is now 0.040 milliseconds. Just a little bit worse in terms of performance. One thing to notice. The string was automatically changed to four knights instead of three because we used a concatenated length inside of our time and timeEnd label parameters. As you can see, console.time is going to let us compare implementations, and that timing feature is going to help determine which code produces the best experience for either you or your users. To demonstrate console.time's usefulness in comparing implementations, we're going to get rid of this newGuy variable that we declare each time in the loop. Remember that extra declaration kind of sucks a little bit. So we're going to get rid of that guy. We're going to scoot over our new Knight call on the constructor, and then we're going to push that down into our push method. So now firstRegimentKnights is pushing directly on the result of a call to the knights constructor with no intermediate variable necessary. Kind of cool, let's see what happens. When we run console.time, we find that we get the time to add four knights now is 0.029 milliseconds, slightly better than that 0.40 that we got before. Times are going to vary, of course, by browser, but ours was just slightly better when not using that extra variable declaration. If this process was replicated 10,000, 100,000 times, you can see that there'd be probably a significant time difference that would make it very useful for your website. One important and useful feature of console.time is that you can have multiple of them run at the same time. Since timers are created and labeled by that string that you pass in to the parameter, you can stack a whole bunch to produce layers and layers of time data. So let's take a look at that. We'll scoot our stuff out here to give us a little bit more space and now we're going to add a second regiment of newbs. Yeah, there they are. Jenner, Tar, Cromer, Stim, Vorn, Rack, Bruck and Arden are the new guys for this second regiment, and they're going to be added to this variable the secondRegimentKnights, which holds a whole bunch of Knight objects for this second regiment. What we're going to do first is we're going to start a brand-new timer that's called "Total completion time". That's going to help us find out the entire amount of time for all of the operations we're about to produce inside this code. Both parts of our existing timer for the first regiment additions are just going to stay in place, like we had them before. Then we're going to recreate that process but this time for just secondRegimentNewbs instead of firstRegimentNewbs. The loop is nearly the same, the process is the same, it's just that the labels are going to be slightly different. And once those additions are done, we're going to stop that second regiment timer. Finally at the very end, we'll just wrap up the master time with that "Total completion time" label and a console.timeEnd. That's going to wrap up the timing of the entire operation. When we run all of this code we get three different lines. The first line we get is when the very first console.timeEnd shows up, which says the time to add four knights was .031 milliseconds. Then later we will get the time to add eight knights is .063 milliseconds. Finally we will get a total completion time of 0.324 milliseconds. That seems kind of weird. What happened? Because .031 and .063 don't add up to be .324. Hmm, what's going on? We got to remember that setting up those timers when it's layered will also take time too, so the production of the timer itself is often included in layered timing data. Be aware of that. Not only will all of those extra layers of time measurement create a little bit of overhead in your master time data, but even running the same test over and over again will not always produce the same values. So what we're going to do here is start at the top and end at the bottom and take out all of those internal measurements for the first and second regiment, and we're going to run that test multiple times. The first time that we run it we're going to get the total completion time of 0.069 milliseconds. But then if we run it again, you can see that that time drops a little bit. Third time, drops even more. But then on the fourth time, we're going to get more than the first time. The point here is that if we want more accuracy in our estimate, we're going to need to use the average of multiple tests. Now, console.time is a good, quick and dirty way to just figure out how much time generally your code is taking, just to get kind of a basic estimate.
Measuring Performance II
Hey, guys! Welcome back to the last session of level two. In this section we'll be learning about how to build a generalized speed class that will average the times that your code takes to run. So in our last section we looked at a quick and dirty way of finding how long your code actually takes to run inside the console using console.time. In this section we will actually be averaging multiple times together to get a really accurate assessment of how your code is performing. Now, to get accurate average measurements for your code, we're going to need to be able to retrieve and use actual numerical time data. This is data that we can actually manipulate, right? So first thing we're going to do here is examine the JavaScript Date object, which will provide us with that numerical data. If we establish a variable here called rightNow and we set it equal to a new Date object, you can see that if we logged out that rightNow variable, we get a whole bunch of date information back. You can see it was Monday, April 10th, 2014 when we called this console.log. It gives you a time value as well as a time zone, and a new Date object is immediately going to capture the current date and time, and that's going to be measured in milliseconds since 12 o'clock am, on January 1st, 1970. Apparently that's when I thought computers should use time. 1970, that's when time began for computers. Now, a cool thing about numerical data is that if we put a unary plus operator in front of our Date object variable, it's going to ask it for the specific value in milliseconds. That means that this line of console.log is the same exact thing as declaring a new Number object on the Date variable. Now, when we get that logged out we see that we get something like one trillion milliseconds, so, you know, there's a few of those in there. Now, since we know we already want an actual number and not all of that interesting date data, we can go ahead and assign the variable to be the numerical version of our new Date object just by moving that plus over to be in front of the call to new Date. So moving forward we can even declare an endTime, a new time on a newDate object, using that same +new Date syntax. We're going to get a millisecond value for that particular time and now you can probably see what's coming and how we're going to use this. We'll declare a new variable called elapsedTime and we set it equal to endTime minus rightNow, and what does that give us? That gives us the amount of time that elapsed between when we first declared our first Date object and our final Date object. Cool, so now we know how to generate Date objects that will hand us data that we can manipulate for time and that will let us see how much time has passed between two events in code. So now with that we can begin to create our very first speed test class. Let's take a look at that. So the first thing we'll do is we'll establish a SpeedTest constructor function, and inside the parameters of that function we will have three parameters. testImplement. That will be the specific code that we want to test for performance speed. We're going to encapsulate it in its own function later on and pass it in as an expression. The second parameter is called testParams, and that's going to represent whatever parameters our test code actually needs in order to work correctly. This might be an array of values, or it might be a single value that testImplement will need in order to work. Finally the last parameter is the amount of repetitions because why? The higher the repetitions that we use, the more reliable our average is actually going to be. So now let's flash out what each individual speedTest object will actually look like. Here you can see we've got testImplement going in a testImplement property of a new object. Same thing for testParams. But then here, in our repetitions property of our speedTest object, we're going to allow the repetitions to be optional and we're going to use our logical assignment best practice to do that. You can see that if the SpeedTest constructor gets past some repetitions, we're going to go ahead and take those repetitions and assign it to the property. However, if whatever user who's using the speed test doesn't pass in any repetitions, we're going to go ahead and just default that to be 10,000 total repetitions so that we can get a good reliable estimate. And finally we'll set up an average property and assign it to zero at first before we have calculated it. Alright, so that's our SpeedTest constructor function. What we're going to do is size that down, scoot it over here, and now we need a method inside of our SpeedTest object. But we're not going to add that to the constructor function, because we want every single SpeedTest object to have this method or access to it, so we are going to give them to the SpeedTest prototype. We're going to use our best practice of adding very commonly used methods to the prototype. So here we go building the SpeedTest prototype. You can see on the inside here we've got an inherited method called startTest, and we're going to use that to begin to start the process of calculating an average speed for some sort of test implementation. First thing we're going to do inside our startTest inherited method is establish these variables. The first two will be our actual numerical Date objects. They will start our clock and stop our clock. It's also that we have declared those variables using a comma separation instead of using multiple var keyword look-ups. Yeah, that's our best practice. That last variable sometimes is going to be the variable that sums up all of the times for all of the repetitions that we do. Next we'll loop over the full amounts of requested repetitions. Notice that we have used our best practice of no repetitive property access at depth. We have cached that value and we'll use that value in our loop parameters. Here's what we actually use, our beginTime variable. Notice what we do. We establish a new Date object but we want the numerical version of it so we can do math on that numerical data so we put that plus unary operator in the front of our new Date object. Next, this is where we run the actual code for this particular repetition inside of the loop. Notice that we pass the testParams into the testImplement function. Then of course we need another numerical Date object in order to stop the clock. Finally we'll do endTime minus beginTime which will of course give us the differential in terms of time. It will tell us the elapsed time. And we'll add that in to the sum of all times for all repetitions. And of course taking the average it's just going to be the sum of all the times divided by the amount of repetitions that we used. Finally, we'll return a message that says the "Average execution across" however many repetitions we used was this amount of time. Cool, so let's test an implementation using our new SpeedTest class. First thing we're going to do though is we're going to build some code that lacks some best practices and then test that speed. Let's see what happens. We'll scoot our prototype down over here underneath our constructor, and then we'll give ourselves some data to start off with. You can see we got our variable firstRegimentNewbs. That's an array list of four guys that are new to the first regiment and need to be added to the list of first regiment knights. You can see there the next variable is the firstRegimentKnights list which has tons of Knight objects inside it. Here comes the code we want to test. We want to loop over all of the existing newbies, and notice no best practice here, we're just going to use that repetitive access at depth that kind of sucks. We're going to do that and see what happens. Additionally, inside the loop we're going to establish a new variable every single time, and that's going to be a new Knight object using the name inside the newb list and whichever regiment he needs to be assigned to, which of course each time here is the first regiment. Following that, once we've got a new knight inside our newGuy object, we're going to push that to the firstRegimentKnights list. That's our simple method for adding all of the new guys as brand-new Knight objects to the knight list. In order to test this block, we've got to be able to pass all of it, the whole block, into the SpeedTest constructor as its own function, right? We're going to create an entirely new SpeedTest object from the constructor and make that a new object in noBPtest. But we need our code to be its own function expression so that we can pass it in to the speed test constructor. So we'll scoot our for-loop down here. We will make a new variable called noBP and wrap it in an anonymous function, its own little module here, and we're going to assign that function expression to a variable. Now once that code is inside that anonymous function, we can very easily pass it around to whatever other function we would like to pass it to. So you can see inside of the SpeedTest call we've now got noBP as the implementation that we want to test for speed. Now, since our SpeedTest constructor lumps all of our test code's important parameters into one testParams property, we need to modify our function in order to be able to use just one array of important stuff. So we've got here, inside of our anonymous function, a parameter called the listOfParams, just one parameter array. We will scoot our stuff down here and we will make that parameter array become the lists for the tests, listsForTests variable. And inside that array, we've got both of the arrays that our testable code will need in order to operate. That list, that array of arrays, is going to be passed in to our SpeedTest constructor to be all of the parameters we need for our testable function. But we now need to modify all of our internal variable names in our function to match that parameter name we created that's just one array. So let's check that out. firstRegimentNewbs is the first index of our parameter array. So that's going to become listOfParams on the zeroth index for both of the times that we access the firstRegimentNewbs data. Scoot that over and now, of course, the first index of our new single parameter array is going to be the firstRegimentKnights array. And we'll scoot that over, bring our SpeedTest up here, and we're ready to roll. Let's see what happens when we test the speed of our prepared, albeit terrible, code sample. Oh, and one thing to note here. In creating our SpeedTest object, we opt to not pass in any repetitions amount, so therefore in our logical assignment in the construction we're going to actually get 10,000 from our logical assignment operator. Cool. So we'll have to start the test by calling the startTest method on our new SpeedTest object. We get average execution across 10,000 repetitions is .0041. Not terrible, but we can do better. Notice, however, that we have about 10 times a speed improvement already over the estimations from console.time. A little bit of an indicator about how much time it really takes to establish a console.time timer. Now what happens if we actually want to specify how many repetitions we're going to use? We want to be a little more accurate so we're going to pass in 100,000 repetitions. We get the average execution is now .00478, and our newer estimate actually brings us ever closer to the truth. We can rely a little bit more on that estimate. Cool, now here's where the money is. Let's go back and refactor our code a little bit and put some best practices in there and see how much our speed improves. First thing we'll do is we'll cache that loop control variable. So we'll scoot our i++ over here, and now we're going to establish that new x variable where we cache the length of the newbs array which happens to be in listOfParams zero. We'll loop over that new variable. Next thing we're going to do is get rid of that internal variable declaration. Not only are we not going to declare that variable, but we're going to get rid of the interim storage entirely. We're just going to create the new Knight object and instantly push that into our new Knights array. Magical and efficient. Now we probably need to change the names of our test function and our SpeedTest object because it no longer has no best practices, now it has some best practices. So we'll call it BP and BPtest. And now when we actually call our startTest on our BPtest object on 100,000 repetitions we get .00274, which is a significantly better execution, especially if this process were replicated a few gazillion times up in a program. An important thing about a simple class like this is it's very reusable for any particular code that you want to test so long as you group the parameters for your testable code into an organized list so that it can be passed into the function that you put your testable code inside.
The Crystal of Caution
Careful Comparisons
Find the Sword of Syntax first For the useful tools that you may need Wear the Pendant of Performance For efficiency and speed Caution's Crystal clears the sky With triple equals and try catch Avoiding stuff that sucks in parsing Better numbers at a stretch At last, the golden shining Mail of Modularity When namespace calls your imports long, defend integrity With polished shields and JavaScript, the treasure trove this is Now raise your sword and strike your shield With these best practices No best practices course would be complete without a section that warns you of the dangers that lurk within the seemingly harmless aspects of the language. So in this level, we'll first examine how to craft the most careful comparisons between our data values so that we get the results that we expect, as well as how to provide our programs with the most effective response to the errors that can and will rear their ugly heads. Next, we'll look at some badly misused methods within JavaScript, as well as some alternate methods for how to avoid the negative consequences of that misuse. Lastly, we'll turn to numbers, within which JavaScript sometimes has some unexpected results, and we'll outline ways to improve our experience with that numerical data. So if you're ready, it's time to look within the Crystal of Caution. Hey guys, welcome back to JavaScript Best Practices, this is level three, The Crystal of Caution. In this section, we'll be examining how to make careful comparisons. Now, you might be aware, but not all equality comparisons are equal. The triple-equals comparator in particular is going to compare both type and contents for us. So take a look at these two comparisons. In this first comparison, we've got the string four being compared against four, the number four, with a double equals. And that returns a true, which is kind of weird, double equals tries to help us out with some type coercion, it thinks you want to know whether four is four. But that's not always the help we want. Over here on the other comparison, we've got the string four being compared with triple equals against four, and we get false, which is exactly what we wanted if we wanted to know whether we have both similar type, as well as contents. Looking at a few more of those, you can see the true and false comparisons with double and triple equals here. And double equals thinks true and false are both one and zero, whereas triple equals does not. That's because, by historical convention within computer science fields, true and false have traditionally represented one and zero respectively. Triple equals, however, it doesn't care, it first sees a Boolean and then a number and it says yo, those things ain't the same, sorry. You want to see something really weird about type coercion, check out this string that only has escaped characters in it. Well, the JavaScript interpreter thinks that you want to know whether that string that has really no contents in it is equal to zero, and so that's going to return a true, which is slightly weird. So the triple equals in that case would help us out and return that those two things are not at all the same. The important thing here is that triple equals seeks a very strict equality, ensures comparison reliability in all of these environments where the data types that you get back or receive from places may be unknown, right, it's very helpful. Let's say we had a website with some fields in it. It was a new registration website for knights that are about to become knights, but have to complete a certain amount of requirements in order to become a knight. Take a look at this function called countEntries. It's going to take in an array of responses from those fields called KnightResponses. It's also going to take in a value that we're looking for, we're trying to count with countEntries how many of the responses are the value in question. Inside, we establish a count variable and we also cache the length of our KnightResponses array, and then we loop over that array to count exactly how many responses are the value that we seek, finally, we return the count variable. Cool, so our knights need to have all these knightly tasks completed, right, in order to be able to participate in their induction in order to be inducted as a night. So I'll fill in my stuff here, and I am Jason Millhouse. And my regiment is 1 and my squad is 12. And I have a squire, my squire has already been assigned to me, and I also have a weapon issued, however, I have not completed my captain's interview yet. So as these fields get submitted through the behavior of the website, we're going to get an array compiled that has all of my responses in it. We've got Jason Millhouse as the name, 1 as my regiment, 12 as my squad and true, true, false for the yes/no answers. Now, if I wanted to know how many completed tasks I had actually performed, then I could call countEntries on my fields responses and tell the countEntries function that I wanted to know how many of my completed tasks were true. Then if I were to log out my numCompletedTasks, I get three, well, that's not right, I've got two yeses and one no, it shouldn't be three, so what happened? You probably can tell. Over here on our function, we've got a double equals comparison of a KnightResponses entry with a value, but guess what happens as the result of that. When I get to that number one for my regiment value, my count variable's going to be incremented because the double equals type coerces my one to be a true value. And when that actually gets compared, it returns true. So let's go ahead and fix that situation, if we throw out the double equals, insert a triple equals now, we get exactly what we're looking for, a two comes back from our console log. That's because the string one is not, in fact, the same thing as the Boolean true, and we get a false through that comparison. The moral of this story, my friends, is that you should always be very careful when you are checking in your comparisons, and that very often, the triple equals comparator is the best practice in most unknown data type environments, and even in known data type environments. The next comparison we want to check out is what happens when we need to verify an object's class? What if we want to execute operations only if an object has been built by some kind of specific constructor, right, or whether it has a specific prototype. Let's take a look at that. Let's say we had two types of armor here. We got leather armor and we got chain mail, all right. Leather armor's got bodyStyle, numBuckles, numSpaulders, chain mail's got what type of metal it is, the link diameter, whether it's got a hood on it, how long the skirt is. Now, where are all of the objects that come from these constructors, well, they're in a variable called armorList, which is a mixed up list of the kingdom's armory's available armor objects, right. And underneath that, we've got our newbs array, which is a list of Knights objects, and these guys ostensibly need some armor in order to be a knight but, well, knights only get chain mail, right. So how can we find which armor objects actually are chain mail using comparisons? Well, if we just loop over the entire armory's list, passing out armor to knights nilly willy, some might end up with leather armor, or even worse, what if they ended up with a helmet for their body armor, that would be really challenging and problematic. So enter the instanceof operator, it's going to help you precisely identify your objects in all cases. You want to use this operator to ensure that you're examining precisely which object your code should expect. So let's build a function here called assignKnightsArmor, right. And we're going to pass in a list of knights, and we're going to also pass in the list of all the armor that is available. We're going to go ahead and cache our array lengths for efficiency ahead of time. You can see we've got x getting knights.length and y getting armorAvail.length. Now we'll loop over every knight that needs some armor. We got a nested loop here, and for each one of those knights, we'll then check through the armor array to find some chain mail. Inside that loop, we're going to check if the armorAvail on a bracketed j for whichever loop index we've arrived at, is an instance of ChainMail, if it's an instance of the ChainMail object. Then we will assign a new armor property to whichever knight we're looking at, notice the ith index there, which signals the outer loop or which knight we're looking at, then we will splice that armor right out of the armor list, and we will return an object from the array that gets returned from splice, and then we will pass that ChainMail object straight into the armor property of whichever knight we're looking at. Notice that the ith index signals which knight we're looking at. Now, since we've taken an object out of our armor array, we need to go ahead and modify our cached length, so that every time we get to that innermost nested loop, we don't go out of bounds on our array of armor. And since the current knight has some armor now, we can go ahead and break out of the innermost for loop. Cool, we got a function, time to give some of these newbies some chain mail, man. So let's fill the list with a little short example, and we'll check out the results of our armor identification process. So let's build a couple sample arrays for our instanceof test here, we'll get our armorList. That's going to have a leather armor, a chain mail, a leather armor and another chain mail. And then we have a newbs array, which got two new knights in it, cool. Now we will begin our assignKnightsArmor function, we will pass in our newbs array, as well as our armorList. So the first thing that happens is for that first knight, we look for the very first armor object, and it's leather armor. So what happens? When we get to if( armorAvail instanceof ChainMail), that's going to return a false. And so we will skip that object entirely, and the loop will move to the very next object, which is a ChainMail. And that's exactly what we want for our knight, and so that chain mail gets assigned to our very first knight object. You can see now that the chain mail pieces out of that array. So the next thing that happens is we break out of our loop so that we can move towards the next knight, because our first knight already has his armor. And then we look again throughout the armor list to find a new chain mail for our new knight. Well, the first thing we get to is a leather armor. That's no good. Then we get to a leather armor again, and that's because the previous chain mail has already been given to the first knight. Finally, we get to chain mail, and that means that our armorAvail instanceof ChainMail will now return true. And so that knight gets a chain mail and we are good to go. That chain mail gets deleted from the array, and if we were to log out our new armor list, we can see we've only got two leather armors in there now. No more chain mail objects, thank you very much, instanceof. Cool other thing, if we were to log out, let's say, our first knight, which would be newbs we'd probably see a bunch of other properties inside that object and also an armor property with a ChainMail object. Cool thing about instanceof as well is that you can check the entire inheritance chain with it. An object happens to be an instance of all the prototypes from which it inherits properties, which is very useful. If you need to make sure an object actually has access to properties before trying to call those properties, as it happens very frequently. So if we built a armor constructor and it had a location and we just gave it a location property, and then we also built an armor prototype that had apparently the putOn function, so that any armor anywhere could call the putOn method. Now we've got a prototype for our armor and a constructor for it. And then we build prototype objects for the leather armor and chain mail constructors, and these new prototypes have as their prototype the armor prototype. We do that using the Object.create method which, as you may know, takes in a prototype upon which to base the newly created object that comes back from the call to object.Create. This makes the armor prototype the parent prototype for both leather armor and chain mail, which makes sense, right. And then over here, if we had a kingsMail variable and we assigned to it a new ChainMail object, and we're going to pass in gold, because the king's mail should, of course, be gold, he's got a two inch link diameter, as well as a hood on that chain mail, and his skirt length is 36 inches for a full protection. This particular usage of instanceof can be very useful if you have to make sure an object actually has access to some properties because you try to call them. Then, if we were to log out, whether the kingsMail is an instance of armor, we get true, and that's because every chain mail everywhere will always be a child of the Armor.prototype.
Exception Handling
Welcome back, friends at home, to level three, The Crystal of Caution. In this section, we'll be examining exception handling. Well, what is an exception? Exception is a run-time error, and we need to distinguish a run-time error from a syntax error, so let's take a look at that. Here on the left, we've got some broken JavaScript in our alarm.js file, you can see we've got an alarm declared nicely with a nice string and a semicolon, we're good, but then we got this alert that's missing a right parenthesis. This sort of syntax error will not even make it past the interpreter for the console, it'll be marked as invalid JavaScript and we'll get a little report back in the console to tell us that we did something sort of screwy. Over here though, in alarm2.js, we have an alert call on an alarm variable with the closed up parenthesis and semicolon, we're all good there. The interpreter's going to think this is completely acceptable JavaScript, but then it's going to run and find that alarm has had no declaration by the time that that alert is reached. That is a runtime error, and it's the sort we want to catch in our code and then control once we have it. So we're going to scoot our run-time error over here and we need to start thinking about what we can do about it. Well, we want to be thoughtful at all times about controlling program flow after run-time errors occur. And like other languages, JavaScript has a very unique mechanism for being able to find, catch and recover from those errors as they occur. To start looking for errors in our code, the first thing we'll use is a try block. What's a try block? It's like a test zone for your code. It's like a stage that you can start running your code on and it gets examined, and if errors come back, then we can catch those and do something about them. And if all goes smoothly here inside of our try block and the global alarm variable happens to exist when it runs, then we're good to go. If something goes wrong in that try block, however, the try block will throw an error message containing details over to its very close buddy, the catch block. You see, the catch block has an error parameter, and as a parameter object within a catch block, that error can be used in any sort of messaging or even in conditions to take specific actions. What does this allow us to do as programmers, it allows us to have broken code exit more gracefully or take better action in the event of some error. Here you can see that if alarm did not exist, then we'll get a popup that says uh oh. And then it reveals that there was a reference error because alarm is not defined. The cool thing about errors is that there are multiple types of errors, which can allow us to take very specific informed action based on which type of error occurs. You want to use JavaScript's multiple error types in order to handle errors as gracefully as possible. Let's take a look at using some different error types by scooting down our code here. And inside of our try block now, we're going to establish a newHallOfFame variable. And inside are going to be two new guys who are going to be added to the knights' Hall of Fame, we got Dask Frostring and Render Tallborn. Now let's say we wanted to add those new Hall of Fame guys to an existing list of Hall of Fame guys, but we would use the concat method, which would just put this array onto an existing array. Well, we hope that that array exists, right. What error types might we expect if this was our JavaScript file, let's take a look. So let's say, for some reason, that list had not actually ever been defined yet, or that the Master Hall of Fame had been redefined as something else in some other file. And if that's the case, when we try to access list to call a concat property on it, we're going to get a ReferenceError. Additionally, if the list is not even an array or a string, because maybe it had been overwritten by something, whomp whomp, then there won't be a concat method to actually call on the list, and so we will get a different kind of error called a TypeError. So say one of those errors actually occurred, well, we need to plan for it inside of our catch block, which will get the error after the try block has thrown the error to it. So if the error that got thrown happens to be an instance of a ReferenceError, then we'll alert a message that says first the error, and then we'll say the Hall of Fame roster does not exist as list, check for a relocation in the master document, that's giving us important information about what to do, it's giving us action to take, directing us as a developer if an error happens. But if the error happens to be a TypeError, right, then we'll alert that error again, and this time, we'll put a more informative message for the type error, which says alas, the Hall's list has no concat method, so please check for a disastrous overwrite. Since we know it's a TypeError, we know we probably don't _____ a concat there, which means that our list is very likely overwritten. So let's take a look at what happens in the first case when we would try to get a reference error. Well, we wouldn't try to get a reference error, but say it happened. We would redefine our list variable as being hall, let's say somewhere globally, our list variable got redefined to be hall. Whoop, there's all of our Hall of Fame existing inside of our hall variable. Well, when that happens, we go to call list, not there, we get a reference error and we get our popup back that says the Hall of Fame roster does not exist as list, please check for a relocation in the master document. So that's the first kind, which is cool, we caught that error and we exited gracefully. Next one happens if list is still there, but now, it's a stupid number, it's 12, there are 12, list is 12, 12 is list. Well, when we get through that catch, we'll get a TypeError and we'll get the exact right popup message back, Object 12 has no method concat. Well, yes, no, it certainly doesn't. Alas, the Hall's list has no concat method, check for a disastrous overwrite. This particular error message sort of directs us exactly where to take action so that we're not left fumbling in the dark about where to start debugging. We kind of hinted earlier at something that might happen here, what happens if list got rewritten to be a string? This code would run just fine, because list as a string definitely has a concat method to call. The code would run just fine and it would avoid the catch block, but likely, it wouldn't do it as expected, so let's check out what happens in that case. Well, down here we got three guys inside the Hall of Fame list that is now a string, notice it's been formatted with some newline characters. And what we're trying to do to that now with the concat method is to put an array on the back end of that string, let's see what happens. Well, the elements of the array get separated by a comma and get instantly added to the string, no space, no newline, nothing, just some weirdy addition of two guys to the back end of our list string, yuck. So we probably need to do something about that in order to make sure that we don't have a string, and in fact, that we have an array, here we go. The thing you want to take note of as a result of that string possibility is that JavaScript will not pinpoint every single error that could ever happen, right, inside your code. Instead, you want to use conditionals and the throw keyword in order to craft the right exception scenario based on what you think your code should do, which means you need to have a real intuitive knowledge of all the places that errors might occur in your environment of data. To illustrate how to use these throw keywords, let's go ahead and scoot our catch block down here and reformat our try block to really pinpoint errors on a better basis. The first condition we've got here is just our standard if the list happens to be undefined, then we'll go ahead and throw a new reference error. That means the list doesn't exist, but we're trying to concatenate on it later, so instead, we throw a ReferenceError as we did before. That's just the same thing that the try block did in our first instance. Next, we've got another conditional that first checks to see if the list is an instance of array. And if that's not true, meaning if it is false, then we will throw a new TypeError to the catch block. Now, it's important to note that, as soon as the try block reaches any throw keyword anywhere, it will instantly stop what it's doing, take that error that it found or that it's supposed to be throwing and throw it to the catch block. And in the catch block, we'll retain control of execution throughout the rest of the process. Something else we should do here now that we've got our errors a little bit more pinpointed and correct, we should modify this final error message down at the bottom where it says alas, the Hall's list has no concat method. We should modify that, let's try to make that more accurate. Since we got a more clearly defined problem up here, our program should be able to provide more accurate debugging information for all cases that we could expect. So now, if our Hall of Fame list was, in fact, a string for whatever reason, then we would get an error message that says alas, list exists, but you know what, it's no longer an array so please go and check to see in your debugging if somehow it got overwritten somewhere. It's important to note that it is our more clearly defined problem that has allowed us to have more accurate debugging instruction for all of the cases that we could conceivably expect in this case. So now, if we had a list that was a string instead of an array, we would get the error message exactly like we wanted. And now, as we went back to correct our program somewhere in our JavaScript files, we would go to make sure that our list had not become suddenly a string or modified this code to match the fact that it is a string. A cool extra thing about the try catch block is that it has a secret friend called the finally block, which will allow us to take action regardless of any error that may have occurred inside the try block. If the try block executes smoothly, we'll go to the finally block. If the try block does not execute smoothly and we go to the catch block, after the catch block, we'll go to the finally block. The finally block just says we're going to do whatever is inside this block regardless of what happened before. So here you can see our finally block, which has got a console.log on the list in it. And that's going to execute whether try meets with success or failure. This is important, because now we will know what list contained at the end of this execution, it may have been that we get all of the new guys added to the list no problem and this log will log out every last member of the Hall of Fame, or we could get undefined if there's an error. Or we could get a string if it was a string, or we could get that crazy number 12. But the point is that we are able to see what happened to the list variable, if anything. What if we wanted to try more than one option within our try catch system, well, nested try blocks, which are totally allowable, can be found within outer catch blocks so that, if your first choice doesn't work, you may be able to just try something else before you just gracefully exit on some error. Let's take a look at that. So we're going to build a new function here called changeInnerHTMLByIdOrExisting, which is the longest function name known to man. And with that function, what we're going to do is look up some text element either by its current ID or by its existing inner HTML. And then we will update the inner HTML. Now here, our existing parameter is going to be optional. That's going to be just an extra search possibility in case the ID for the element we're looking for is not found. So now we've got our try block here inside, and in that, we have a variable called newElement, and we're going to set that equal to undefined, we're going to use that later if we need to make a new element. Following that, we're going to try to set the inner HTML of the element that we find with the ID to whatever the update is. In other words, if the element is found, we'll just update its inner HTML. Now for the errors, what happens if we catch an error from this? Well, the first thing we want to do is not exit the program or return a message or anything, we want to try something else. So we've got a try block that happens immediately after some error in our first try block has been caught. In this case, we may know the existing inner HTML instead of the node's ID, and it may have been passed in as an optional parameter, so we want to try searching based on the existing inner HTML. First thing we're going to do inside of our nested try block is we're going to get every last element of the document using that star inside getElementByTagName. We'll pass all those to an elements array. And then we'll search each of those elements for a matching inner HTML, and if we find a match, we'll change it and exit. Another cool thing we'll do is that, since we don't have the ID variable, right, we couldn't find it, then what we're going to do is record whatever ID is at that text element inside our ID variable for later use. But inside of our loop, if we ever reach the end of that list, then the element location has failed and we need to do something. And what we'll do is we will throw a new custom error, that's right, in addition to all of those native JavaScript error types, we can create custom errors with all these custom message properties, and we're going to use that custom message property inside of our nested catch, which is upcoming. Now, in our new nested catch block, you can see that our error parameter is called error2. That's because we want to distinguish it from the previous error, we need to give those two parameters, those two errors different names for use in their blocks. What we'll do is we'll alert the message associated with error2, and we'll also tell the user that we are creating a new text node, that's because if no element was found with our existing inner HTML or the ID in this case, then what we're going to do is we're going to make a new text node for use somewhere outside the function, and we're eventually going to return that value. Lastly, we will get to a finally block, and remember, the finally block is going to execute regardless of what happens in the try and catch nested blocks. Here, you can see in our finally block that we check to see if the newElement is no longer undefined, and if it's no longer undefined, what do we know? We know that we made a next node. But if newElement was undefined, it means we did not create a new text node, because it already existed, the one we were looking for. So what we do is we log out a notification that the requested element was updated, and what we'll do is we'll use either the ID if it exists, or the existing HTML that we found the element with. Notice our cool best practice of using default assignment to the existing if the ID was never found. So let's say, in some website, we called changeInnerHTMLByIdOrExisting, and we called it with an ID of age. And let's say that that age ID did, in fact, exist. We also passed in an update, meaning we want the new inner HTML to be age is 35, and the old one, which was age is 34. Well, what will happen in this case if age did, in fact, exist? First thing that function would do is go to its first try block, and it would find the element no problem and set the updated inner HTML to be age is 35, and we get that logged out. But what happens if age does not exist? Well, the first thing that happens is we go to the try block and it doesn't work out because it never finds the element with that exact ID. So it'll throw an error and it goes to the next catch block. Inside that catch block, we first go to a nested try. So it searches through all of the existing elements, but does, in fact, find an element that has an existing HTML of age 34. So what happens, we get a check and we roll all the way to the finally, because we break out of the loop and don't need to go to the next nested catch block. Once we're in the finally block, we log out that we modified the element age 34, meaning we chose the existing label in our logical assignment with inner HTML age 35. So before, we chose the ID to log out because it was available, but in this case, we're going to default to the existing inner HTML because the ID was not, in fact, available. And lastly, we look at the situation where age does not exist as an ID anywhere, nor does age 34 exist as some existing HTML. So now let's check out what happens on this run in this situation. The first thing we do is we hit the first try block, but there is no age ID anywhere. So we go to the catch block and we assemble all of the elements, check them all out to see if there is an existing HTML that has age 34, there is not. And so when we don't find any element with that existing HTML, our new custom error is going to get thrown to the nested catch block. Then we will get a new message alerted that says yo, an existing element was not found and we're creating a new text node. Then we will pass control to the finally block where, when we discover that newElement is no longer undefined, we will just log out that we are returning a new text node.
Stuff That (Sometimes) Sucks
Hey, guys, welcome back to section three of level three JavaScript Best Practices, and what would a best practices course be without a section on what not to do. And that is this section, Stuff That (Sometimes) Sucks. And the first kind of sucky thing that we're going to look at is the With statement. JavaScript's with keyword is sort of unreliable and it's often very expensive too, so it's generally avoided in practice, let's take a look at what it does and how to avoid its pitfalls. Here, we've got a drawbridge object with some properties, it's got soldiers and there's eight of them there, it's got a capacity of 20, meaning 20 people can go on this object, it's also got an open method which will, of course, alert a message that opens the drawbridge. Now, if I were to use a with block on this drawbridge object, what it will do is take the entire encapsulated environment of the parameter object, in this case, the drawbridge, and use it to build a new local scope within its bracketed block, which is kind of processing expensive. You can think of that with keyword as asking the interpreter to do operations with the name of this data container as the header syntax on each piece of data, sort of. Right now inside this block, because I am _____ on the drawbridge, I can call the open method and no object name is necessary when everything in the object is already treated as being local to that scope, that block. And I get my alerted message that the drawbridge has opened, (groans). Now, you might think wow, cool, yay, I don't have to use the object name, it's so great. Not great. What happens when I try to build a new property close right here inside that with, I'm building an anonymous function there and I've got the close mechanism, it's going to go yun yun yun yun yun yun clack. Building new properties in the object on the fly is not going to work like you might expect it to, since we seem to be in the scope of that object, no, let's see what happens. Turns out that, if we actually want to build some property on the fly like that, it's not considered as a new property on the object, it's, in fact, considered as some new random global variable to be created. Yay. The thing about that is though that any new variables are, of course, added to the surrounding scope, which is slightly counterintuitive and certainly not what we were looking for, so beware of that. Thus, if we actually did want to add that to the object scope, we've still got to do that either right upon construction or with a declaration or with some on the fly dot or bracket syntax. Now, with has sort of an admirable goal, it's trying to limit redundancy because, you know, nested objects are very frequent in JavaScript, and with is trying, trying to help avoid all of that deep access repeatedly, and typing all of that access over and over again, right. We're going to scoot our drawbridge object a little bit further inside of some other objects here, and see how with is sometimes used poorly to handle these nested scenarios. You can see that our drawbridge is now contained within a keep, right, and the keep has soldiers of its own and a capacity of its own, and the keep itself is contained within a castle object, which has soldiers of its own and capacity of its own, right. Drawbridge is way down in there. And over here on the right, we're going to write some code. We're going to establish a reinforcements variable, that's 12 guys, these were some guys that need to be reinforcing the drawbridge. So we're going to write if the castle.keep.drawbridge.capacity is greater than or equal to the castle.keep.drawbridge.soldiers plus reinforcements, which is awful and terrible, right, then what we're going to do is we're going to call castle.keep.drawbridge.open(), obviously, you can see that this is really irritating to type and keep. Just typing forever on, right, which is awful. So if we needed access to the drawbridge object from the global scope, it's going to be very redundant to try to keep getting to that. With is trying to avoid all of that. So what some people might do here is put all of this code inside of a with block and make the reference object be castle.keep.drawbridge. Let's check it out. So all of those castle.keep.drawbridges go away. Now, this is much more terse and legible, right? Makes a lot of sense to use with, every day, all day. Problem here is that with will always make it unclear which properties or variables are actually modified elsewhere. If we can't read a program, right, and be confident that we know what's going on inside of any block of code, then we are never really sure the program is working like we intend or like we desire for it to. If you've got a developer gal coming in here to look at this code, it's not going to be immediately understandable to her where the soldiers or the capacity was located in this case, we happen to know, the designers of the code happen to know, but anybody that's trying to maintain your code may not know, and that makes it very difficult for large scale projects. In particular here, check out that soldiers that's getting modified with the plus equals reinforcements. We're actually not sure where that soldiers variable is getting modified. What if the soldiers property was not actually in the drawbridge? Maybe it gets added on the fly only in times of war or something like that. So what we want to give you here is this best practice of using variables to cache your objects to avoid the with pitfalls. This is just like the caching that you saw in the loop optimization segment, right. It lets us avoid a bunch of typing, but it's also very clear in its indication, let's take a look. So what we do here is we show the with block the door. Goodbye, with, pieces out. And now we're going to establish a new variable called o and we're going to assign to that variable the castle.keep.drawbridge object. That means that entire object is now contained within the single letter o. So now when we scoot our code over here and we drop in a bunch of o dots where necessary. Now, with all of this cached clarity, the team members on our very large project will be able to understand all of our code's functionality more precisely and understand where stuff comes from and what you're referring to in your code. Also, yay, bonus, no lengthy typing, no long nested object names are needed in this case. Moral of the story, cache objects were possible and avoid the with statement. The second somewhat sucky thing that we want to talk about here is the eval statement. Now, eval kind of gets a little bit of a bad rap in the JavaScript field, probably for good reason, because it can very much affect legibility in your code, as well as significantly impact your ability to debug and incur a bunch of performance penalties for you, which are often terrible, so let's take a look at why eval should be avoided. Take a look at this function here called assignRegimentMotto, it's going to take in the number of the regiment as well as the motto for that regiment. Now, the eval method is going to take a string in as a parameter, any string, and it will start up the JavaScript compiler and treat that string as if it was some line of code to actually execute in JavaScript. If we passed in the regiment number two, as well as the best of the best, which is their motto, into the assignRegimentMotto function, this is what happens. The eval method takes all the pieces of that string and puts them together into one string. So what we get out of that is regiment 2, some object somewhere, .motto, referencing that motto property, becomes the string The Best Of The Best. This may seem great. But it really opens up a lot of possibility for error. What if there was, for example, an apostrophe existing in the motto? For example, what if the first regiment's motto was The King's Own, see that apostrophe in there? Well, what happens here is that the resulting code, when it finally gets eval'd, will actually be invalid because of that extra apostrophe. It's going to make the compiler think the string is complete, right, until it sees more stuff and then it's going to mark the code as invalid JavaScript. Something else to note here is that we may not have any idea at all what broke our code, especially if the data that gets passed in as motto is not something we ever examined. Was it number that was busted, was it motto that was busted, was it something else? You know, it gets really in the way of us being able to debug. Eval can be useful in a tiny fraction of the ways that it actually gets used. For example, we use it here in our executor to evaluate your code at Code School. But mostly, eval is like taking a bazooka to a beehive, okay, it's bad news. You want to try not to do that. Though it may end your existing problems, it's probably not the ideal way to solve that problems, and furthermore, you may end up with more problems than you started with. But if eval is a must for some reason, you want to eval as little as possible. It might be useful for dynamic code or uncontrollable data, but it's still treating the string as a program to very expensively compile. So in those cases where we can't avoid an eval statement for whatever reason, and we usually can't, we at least want to minimize the operations that that eval statement needs to engage in when its little mini program starts up. That's going to benefit us in having added debug capability. You can see here that, instead of including the entire portion of the string inside that string, we only eval the regiment and its number and know that the motto will be available. Thus we can just take the motto that we pass into our function and assign it to that motto property once the regiment object had been evaluated by eval. And now, if I were to log out console.log(regiment2.motto), you can see that I get The King's Own, complete with apostrophe, no problem. And the best practice we want to give you here is that, for all of those basic mappings between objects and numbers, you want to instead use your data structures. Eval is most often misused with just that sort of mapping, trying to get objects with numbers on them. So we want to make sure that you try to use arrays, which are much more efficient, let's take a look. We'll start up a variable here called regiments and we'll put all of the regiment objects inside that array, and then there's no need to number the variable name if your objects are already in order. You want to build your own data with all of its usage in mind. Inside of our function now, we can just regiments and then call the index on the number passed in, dot motto equals the motto. And instead of eval, we can use that associative nature of the array to build all the dynamic mapping that we could ever desire. Really cool, referencing an array is much faster than parsing and running an entire new program within your program. But, but, but what if I need to read and write JSON data that's all stringy? Chill, homie, using eval to parse your JSON is typically regarded as very vulnerable, often very unsafe, right, because eval is going to evaluate any script that gets passed in, let's take a look. So here, I've got some stringified JSON data being assigned to the variable regimentsJSON. You can see inside this stringified JSON data that eventually is going to become an object that contains other objects which are the numbered regiments. If I wanted to eval that and pass it back to a regiments value, I could, but what if this data came from somewhere else, as does a lot of JSON data, well, that could be a potential vulnerability, right, because you have no idea what's coming in in terms of a script through code injection. Bad news avoided. But what can I do if I actually need to use JSON data that has been stringified and I need to parse it, well, you can use JSON.parse() to ensure only the JSON is accepted. JSON.parse() will only recognize JSON and not compile any scripts, avoiding all those security issues from malicious incoming data. Additionally, there's going to be some libraries that used to employ eval under the hood, but now use JSON.parse in all of those places, and that includes jQuery. You can see here that, if I call JSON.parse on regimentsJSON, all of that code would become a very nice regiments object. The moral of the eval story is that there is usually always a way to circumvent the use of eval through the proper use of data structures or other methods designed specifically to do what you're trying to use eval for. So try to stay away from it. Next up, the third slightly sucky something that we would like to make you aware of is leaving off your brackets in your code, just because we can leave curly braces off of a single statement block of code does not mean that we should, because it's cool. Check this out. In JavaScript, I could write if(isKing), then I could make the weapon Excalibur. Else I could make the weapon the longsword. Notice I've got no brackets of this code, because it is true that when a condition or a loop has only one statement to execute, the brackets are not necessary. But using curly braces is not just about excellent code organization or excellent code legibility, although it is about those things, it's also about being a very good team player, right. It's about having very good code citizenship, and here's why. But what if new code needs to be added, man? If you require bracket analysis in order to ensure that every new bit of code is properly scoped to the right block, you will be very unpopular. So say there's a new guy, right, and he's coming in to work on my terribly unbracketed code here. And he needs to add some functionality that's been requested, so he puts these two extra statements in to both the if block and the else block. Turns out though that this else is now going to cause an error. That's because it looks for a preceding if block and doesn't find one. What? I see an if block there, oh, guess what. Since there are no brackets around those extra two statements, that else block doesn't know which if it's associated with. That's because those two statements he added in the if block are not actually a part of the if block. But even though we found that error through the else erroring out, missing brackets don't always generate errors, sometimes we get perfectly valid JavaScript, especially in the example of conditional blocks, and then we get a whole bunch of undesired executions. Let's take a look. So we'll get rid of our else block here. Now I can see we've just got the if(isKing) portion. Now, even if isKing is false, right, well, we will skip the weapon equals Excalibur, but we will get the alert to be called. We will also get a call to remove from armory the sword Excalibur. That's because, without the else to trigger an error, the JS interpreter just sees this code written like this. If isKing, assign Excalibur to the weapon. And then who cares if it was his king or not, do these two steps, alert this message and removeFromArmory Excalibur. So undesired executions often suck, right. So please, be cool, bracket your code. It's better for organization, people can read your code better, and it will often prevent errors you did not know were going to happen. Brackets are a two character, tap tap sacrifice that is going to help you in the long run.
Number Nonsense
Hey, guys, welcome back to level three of JavaScript Best Practices, this section, the final section of level three, is about number nonsense. So in JavaScript, decimals are actually kind of crazy. Because JavaScript uses binary floating point values to handle all of its decimal based operations. If we pull up a little console.log here of a simple addition, .1 plus .2, we'll, that's just .3, oh, uh, what, there's a four, there is a four, there was no four, there is a four now. I don't know where it came from, well, I kind of do, it's binary floating point values, right, which are used primarily for performance, because they do enhance performance in a lot of ways, but there's definitely a trade off between performance and accuracy in this case. Taking a look at a couple of other examples, if we did .1 plus .2 plus .3, we get .6, oh. There's a one there, there's a one, there was not a one, now there's a one in that spot, crazy. One of the crazy things about binary floating points is that they're not even associative in this case, if I tried to add .1 and .2 over here in parentheses and then add .3, well, I get the same exact thing that I got before without the parentheses, but if I try to add .1 to the grouping of .2 plus .3 (gasps), magically, I get what I'm expecting, .6, fine, I'll just jump off a bridge, everything will be just fine. Now, floating point arithmetic using binary numbers inside of a computer's arithmetical logical unit, that's slightly outside the scope of JavaScript best practice, wouldn't you agree? So what we're going to do is give you a little bit of resources at the end of the course for you to go research floating point arithmetic, because all the developers should have a passing familiarity with it. Instead, here in this course, we're going to give you some ways to kind of constrain JavaScript's occasional number nonsense, as well as get consistent results regardless of the internal operations. So first, we'll talk about a few methods that help improve your decimal visualization. First, there is the toFixed() method that's going to allow us to select precisely the amount of decimal places we want to display. Over here, you can see we're storing the result of our crazy .1 plus .2 addition in a variable called number. And then we're going to log out num.toFixed(1), that means we want exactly one decimal place to be shown on our number, and we get 0.3, exactly what we would like. And you can stick any amount of decimal places in there that you prefer, if we pass a four in to num after we have created a new addition on .1, .2 and .3, we can see that we get .6000 for four total fixed decimal places. Important to know about toFixed() is that it's going to round to the very last indicated position that you have provided, so if you're dealing, for example, with percentages of money, then toFixed() can handle that hundredths rounding for you at any time. Here we've got a function called tax, it's going to take in a price of some object, as well as the tax percent that that object is subject to. On the inside, you can see that we return the price times percent divided by 100, which will give you exactly the tax that you need, but we're going to return it to a fixed decimal place of two, that way, it is in money terms with two decimal places. You can see here, if we called the tax method on nine dollars and 85 cents, as well as with a 7.5% tax rate, what happens on the inside is we get 9.85 times 7.5 divided by 100, but that's going to give us .73875. Now, our toFixed() with two in it is going to look at the third place to ensure two places will be correctly rounded, and since eight is greater than five, the three will increase to four, and we'll get .74. But look, that's a string. Hmm, what can we do about that, how are we going to use a string numerically if we wanted to do other operations? Because if we had a mailed glove that cost nine dollars and 85 cents, as well as some armor tax that was 7.5%, and we wanted to know the total price of this mailed glove in this shop, we would add the mailed glove variable to the results of our tax method, thinking that we would get some number out of the tax method, but what that would actually do, oh, that escalated quickly, would give us 9.850.74, what, weird. That's because it tried to concatenate a string to a number. That's where we'll need a new method to help you use the rounded value in further math operations. A cool method that will help us out with that is called parseFloat(), it's going to turn strings that have decimals into numbers to be used. A combination of toFixed() and parseFloat() will let us use values of exact length in all of our math operations that we might desire. So you can see I've added a parseFloat around my mathematics, as well as my toFixed, and what that's going to do is it's going to return an actual decimal value back from the tax function, so now when I pass a 9.85 and 7.5, I'm going to get .74 the number, 0.74 the number, instead of 0.74 the string. That makes it very usable in the addition math that I've got doing with mailed glove. So you can see, when I got that out, I'm going to get 10.59 in money, and now we're good for display or other usage inside of totals. ParseInt() is also a very valuable method that will convert numerical strings. But instead of looking for a floating point number, parseInt() is going to seek the very first available integer on the front of any string. So here you can see, if I've got parseInt on a string, 88 is going to return a very nice 88 to me. But if I pass in a string that has an integer on the front, parseInt() is going to try to help out. It's going to try to provide any integer that begins a string of other characters, that's slightly weird, very often dangerous. Same thing with parseFloat() too. If I pass in a sentence here, 3.28084 meters in a foot, parseFloat() is going to look for the termination of all of the numbers after any decimal point is encountered. Something to note, if a string does not begin with an acceptable value for either method, however, you will get that JS value, not a number. More on this in a little bit. One thing we want you to know about parseInt() is that it will trim off any decimals it encounters without rounding, so if I were to pass in this string, 9.85, I'm going to get nine back. That may not be what you were expecting if you thought 9.85 should become 10, so watch out for using parseInt in a rounding situation. Now, although parseInt() is often super valuable, it can cause some unexpected value errors that we want to make you aware of. That's because parseInt() will accept octal or hexadecimal or decimal values, thus we want to use this with a little bit of caution here, check this out. Say that we've got a userAge variable that takes some data from a user, but that the user, for their age, actually made an error in typing and put in 021 instead of 21. If we use parseInt on userAge in modern ECMAScript 5 systems, it's going to give you exactly what you want. It's going to trim that zero off the front and make it a 21, pretty cool, but if we use parseInt on userAge and we're in an older system, it may think that you are trying to pass an octal value, which is base eight, and it's going to try to help you out with a conversion back to the decimal value, and it's going to give you a 17. Now, if this was a dude registering on a cruise ship and he put in 21, but the system thinks he's 17, he's going to have a uniquely different experience there. Now, this situation very much points to the idea of progressive enhancement in Internet technology, which means we need to keep all of our users' possible errors in mind at all times. When dealing with our string to number conversions, it's going to be very prudent, very helpful, cautious to make sure that we pass in a defining radix value, the radix value is going to tell parseInt() exactly which base in which you want your value to be treated. So here you can see, we've got a parseInt() method on that 021 string, but now we're going to pass in 10. And that's going to say yo, I want this to be a decimal value, whatever you get out of it, so parseInt() is going to take that radix value, look at it and say okay, decimal value, got it, and send it back and we get 21. Always do this when you cannot be assured of a browser version or a user's input, in other words, forever. Another cautionary tale we want to tell here in this section is that of testing for number presence before you try to do an operation with that number. Now, using not a number to check of values actually exist, that seems like a good idea, not a number, if I can use not a number, that should work, right. Usually, it tries to kill you. Take a look at this, if I do typeof not a number, that's a number. The type of not a number is a number. So okay, so if I got console.log not a number triple equals not a number, I'm trying to see if not a number is, in fact, not a number, and guess what that's (gasps), false, not a number is not a number is not not a number. Something, right, crazy. And then, if I use the is not a number method, which a lot of people turn to, on the string 42, that's false because this is a string, this is a string and it's not a number. It's not a number because it's a string. I don't know. Yeah, it's kind of crazy in the number environment, especially with not a number, and it turns out this is not a number method is actually looking strictly for the value not a number itself. (gasps) Fun. What we want to give you here in terms of best practice is please, for your own sake, do a double check to avoid insanity. If you're unsure about the data type, but you've very highly reliant on the fact that it is a number, you got to use typeof and is not a number as a best practice, let's check that out. So if I build over here a function that says isThisActuallyANumberDontLie, and I pass in some data, right, what it's going to do is it's going to return the Boolean result of this compound conditional in here, first thing it does is it checks to see if the type of data is, in fact, a JavaScript number value, right. Not only does that have to be true, but we also have to make sure that the data is not, in fact, not a number the value, NaN, right, because look up at the top. Typeof not a number, that's a number, so if I just check to see if the data is a number, I could be screwed is my value is actually NaN, right, so we want to do both of those checks to actually make sure that we have the number that we're looking for. Checking that out over here, if I call isThisActuallyANumberDontLie on 640, I get a true because cool, that's a number and it's also not NaN, right. If I call that method on the string 640, well, the first part of my condition, my compound conditional, breaks because typeof data is not, in fact, a number, and so I get false. And now here's where the money is, this is where you have avoided getting any wrong answers back. IsThisActuallyANumberDontLie on not a number, that's going to be false because the second part of our compound conditional will not be correct. Now, if you want a little leniency, especially for form data, which we know can come back crazy all the time, then you want to use parse methods. If numerical data may show up some time as a string, then you want to parse your data before you do your check, and also add additional checks. So let's check it out. We're going to build a function here called checkValidZip, we're going to check on a valid zip code in some field. First, we'll actually get the entered zip code from the value of the zip ID element. Next, we will try to parseInt() on that entry and pass it to the userZip variable, then we'll get a try catch block going. Oh, we're back to those, huh. If isThisActuallyANumberDontLie on userZip, meaning we do actually have a number here, then what we're going to do is check to make sure the length of that zip code is only five, so we've taken the userZip, we've fixed it to a zero decimal length, and if that length happens to be five, of that number, then we will actually get the number five out and we will return true, our valid zip is cool. Otherwise we're going to throw an error that says nope, it isn't good. And then, in that second else block, we're going to throw an error if our isThisActuallyANumberDontLie method found out that our userZip was not, in fact, a number. And then in our catch block, we'll just handle the error gracefully, telling the user to please enter a valid zip, dude, and return false from checkValidZip. We could put a bunch of other error responses there as well. So now over here, if we got a zip code field and we enter 32803, then we get a true value back because we have a length five on our zip code and it's actually a number. But if, when we were entering that zip code, we hit 3280 and our finger was actually hitting this Shift key and we put three down and it gave us a number and we entered that, we would get a false back from our checkValidZip because we do not have an actual number going on, yeah.
The Mail of Modularity
Namespacing Basics
Find the Sword of Syntax for us For the useful tools that you may need Wear the Pendant of Performance For efficiency and speed Cautions Crystal clears the sky With triple equals and try catch Avoiding stuff that sucks And parsing baton numbers at a stretch At last, the Golden Shining Mail of Modularity When namespace closure imports long defend integrity We'll polish skills in JavaScript The treasure trove this is Now raise your sword and strike your shield With these Best Practices Well friends, your journey here is almost complete. In this last Level, we'll be taking a look at the Module Design Pattern in JavaScript. First, we'll look closely at the basics of a simulated namespace in JavaScript, which is the foundation for any module, thereafter we'll look at how to create public and private state data for the use of anonymous closure, which can sometimes be very hard to grasp. Next, in keeping with our Best Practices of clarity and data protection, we'll examine the use of global imports, which will allow us to carefully and clearly use external data inside of our modules. Lastly, augmentation will wrap things up, so that you can add functionality and properties to your modules, even after they've been built inside other files. So you've got your Sword, you've got your Pendant, you've got your Crystal, now it's time to don The Mail of Modularity. Hey guys, welcome back to Level four, the final level of JavaScript Best Practices, The Mail of Modularity. In this first section, we'll take a look at the basics of a namespace. You write a JavaScript file, I write a JavaScript file, everybody writes a JavaScript file and conflicting code within those files can cause overwrites, JavaScript files often have conflicting global elements, if they're not built well and that can overwrite existing, very important data, let's take a look at that. So say we had a Hall of Fame website document here, you can see various HTML elements, as well as some unordered lists and some script files, that we call just before the end of the body tag. Let's say that this first script was built by the same author, who built the entire HTML structure and that's going to report the current Members of the Hall of Fame. Later, she asks a colleague to please build a short file, that's going to list just the requirements for the Hall of Fame selection. So in the first file, the halloffame.js file, we've got a list of all the guys that are in the Hall of Fame currently, to add those guys to the unordered list in the HTML document, that has the id hof, H-O-F, we'll get that element by id and store it in a variable called H-O-F, hof, next we've got a fragment, which will help our best practice of touching the DOM as little as possible and then an element, that we will use to add a list item, but then our friend comes along and we get the requirements.js file and inside that, you can see the reqs list there, an array of stuff that a knight has to do to get into the Hall of Fame, that's be a Cool Kid, Slay the Dragon, Good at Swording, right, stuff knights should be able to do for sure and then though, we have a new list variable being declared and assigned, that's going to pick up that unordered list under selection requirements with the id of reqs, R-E-Q-S, now the existing list, that was in the previous file gets overwritten, due to hoisting, both of those variables would be global and since one was declared after the other, the second overwrites the first, now is that a big deal here? Well maybe not in this case, because the first list is already done being used, everything that had happened inside the Hall of Fame file is already done and ready to roll and so declaring that new list variable inside of the requirements.js file is not such a huge deal, but there are ways in which this could become a huge deal, so let's take a look at those. What if halloffame.js only really provided a global method for displaying the HOF Members, instead of just displaying them immediately as soon as the script file was loaded and run, instead what it does is creates a global function called displayHOF, display Hall of Fame, so we scoot our reqs list down here and now we're going to put a button under the Honorable Members' header and on the click of that button, we're going to actually call using an inline JavaScript, displayHOF, so when the button is clicked, that's when the Members of the Hall of Fame actually get displayed, now what kind of problems might this cause? Well, by the time that both of those script files have been retrieved, loaded and run, displayHOF, the new function, the global function is going to be in memory and ready to be used upon the click of that button, but now that that second requirements file has created that second list global variable, it overwrote the first and so displayHOF would no longer find the exactly correct list of knights in the Hall of Fame, instead it finds that other global created in requirements.js, well, what can we do about that? Well, enter the simulated JavaScript namespace, though a namespace is not really native, so to speak, to JavaScript, the namespace concept, that is found throughout programming can limit global impact and also provide us with some data protection. So to build that namespace, we're going to rewrite our halloffame.js file, the first thing that we do, the key to creating a namespace is a single, global object and that's commonly called the wrapper for the space, for the namespace, by convention, you will very often see a namespace capitalized entirely. Now, all the variables that were formerly declared in the global scope will now just be properties of the HOFMASTER namespace, additionally the displayHOF function will also belong to the the HOFMASTER namespace, which means we'll need to reference the calling object on all the needed variables, using this. Now that that function and all of the necessary variables are actually encapsulated within the HOFMASTER namespace, we're going to need that HOFMASTER name as a header syntax, in order to call that displayHOF method, what does that mean? It means that the name of the namespace will act as this shield, this armor around your data, by using that mini environment, sort of a data container, it's going to add a layer of protection, that we don't always get, if we just incorporate everything as a global variable, so now if our globally-unfriendly file tries to make an impact on that document scope, the master information, the one we cared the most about, the data that we enjoyed the most, we wanted that to stay very protected, that doesn't get impacted at all. Now ideally, all of your JavaScript files will incorporate a namespace of some sort, because the namespace is really going to reduce your global footprint on the entire application, this is very useful for very large web applications, it's also going to keep your data grouped very carefully around their intended functionality, that's really important, so here you can see, to rewrite that requirements.js file, we've given it a REQUIREMENTS namespace, notice All Caps, and inside there of course are the bunch of properties and methods, that the requirements, things need in order to be produced in our HTML file, what do you notice here? Well, namespaces tend to remain agnostic of each other, right, unless the file builders are building those namespaces specifically to work with each other and that's very useful for data protection. Another thing to note about namespaces, that's cool is that nested namespacing is very frequent in JavaScript and especially in a module pattern, more of which we'll be discussing as the sessions move forward in this Level. Now nesting namespaces provides even further organization, even further grouping and protection, as well as keeping the variable names very intuitive, if you need them to be, this means that you could have multiple list variables inside of multiple namespaces, without each impacting the other. For example, here we've got a new BIOGRAPHIES namespace as a property of the HOFMASTER namespace, a new layer of scope groups all that related data, but it shields it by requiring all of the namespace references, you can see here in my call to HOFMASTER.BIOGRAPHIES.unfoldBio, I can pass in a list variable, that incorporates the knights, who are in the Hall of Fame, but I need to use that HOFMASTER reference, in order to make it happen, that's going to distinguish it from the HOFMASTER list, which you can see holds the knights and the list inside of the BIOGRAPHIES namespace, which holds only some useful list of biography data about each of the knights that are in the Hall of Fame.
Anonymous Closures
Welcome back, hope you enjoyed working with namespaces, we're on inside of our module pattern towards Anonymous Closures. So far, we have only seen a module, that has public properties, the thing with the namespace though is that you really have to hope that no one else ever uses the name you've created for your namespace inside your application. Take a look at this Armory object right here, the ARMORY namespace, we can infer because of the capitals, now this namespace has a bunch of public variables and methods, which can still be accessed by any code, that happens to know the name of the space and its properties, what if we don't want that? What if we want some privacy to our data inside our namespace? First, we need to decide which properties should be public and which we don't want anybody to see and should be private, so taking a look at these, we've got a weaponList and an armorList and since an accurate list of weapons and armor is really, really important, right, to accurate Armory service, I mean, when you run your Armory, I'm sure that that's what you need, these arrays should be very private. Rolling on down, you see makeWeaponRequest and makeArmorRequest, well that seems to be something that should be public, because the whole reason an Armory exists is because we want people to be able to make requests to get weapons and armor out of the Armory, right and then finally, removeWeapon, replaceWeapon removeArmor, replaceArmor, that's really messing with our data, with our lists, right, so we probably want these to be private as well, because making any modifications to the master list should be a task that only the module takes care of and only the module can call into being. This is an excellent case of how public methods and values often and sometimes should be triggering the use of private methods and values, so in our case, our public methods are going to signal the private methods to safely modify the private data. Here you can see each request method, meaning makeWeaponRequest and makeArmorRequest, each of those is going to make some reference in its code to the remove/replaceWeapons, those are going to have access to the weapons and armor lists, that makes closure very valuable, let's see how. The closure feature in JavaScript, which you may remember from JavaScript Road Trip, has a feature that will allow us to privatize properties. As a first visual step, check this out, we'll wrap the entire set of properties in an anonymous, immediately-invoked function expression, stay with me on that, so what we got here is function at the front, but notice it's wrapped inside of a left parentheses and then at the back, we close that left parentheses with a right parentheses and then immediately call the function by providing another calling set of parentheses, this is an immediately-invoked function expression, which you probably saw or remember from Road Trip. Now we will turn all of our desired private properties of the old ARMORY namespace, we're going to turn those into local executable code inside our new function, right, and those local values and methods, that now belong to the function will be closed up into the Armory's namespace, once the Armory object gets returned. Here, the list of data become local variables for the immediately-invoked function expression scope, that's going to make them private, we'll do the same thing for these function expressions down at the bottom, removeWeapon, replaceWeapon, removeArmor, replaceArmor, we want all those to be private, so we're going to make those local executable code as well, again, these will belong only to the function, instead of directly to the namespace, stay with us. Next thing you should probably do, although it's not really required, it's just good habits, is to pull every private value and method to the top of the function, that's going to help us with code organization and it's going to put all the closure values near the top and near each other for easy reference, so let's scoot those over and here is where the money is, in order to make some of the properties public, which is obviously our remaining ones, we're going to return an object that holds those properties, so let's add those public properties to their own object and return it and that becomes the ARMORY namespace, once the immediately-invoked function expression finishes and returns. What you can see is that once the function completes and returns that object, it will be immediately handed over to the ARMORY variable and become the new ARMORY namespace, complete with public properties, makeWeaponRequest and makeArmorRequest, as well as all of that private data, that no one will ever see. What we want you to notice about this really powerful element of the module pattern is that the closure now produces all of your desired private methods and values, all of the functions, local variables get pushed, get bound down into the returned object, into that scope, but those properties are never actual properties within the object itself, they're there though and they're visible too and able to be referenced by only the members of the object's local scope and with that, the basics of our module are actually now complete, our sensitive data is private by closure and our public properties are accessible through only the namespace. So now, if we call ARMORY.makeWeaponRequest on the weapon, Excalibur, well, the ARMORY namespace, which is that small object there calls its makeWeaponRequest property method, next makeWeaponRequest will call removeWeapon, which is invisible, in order to try to get Excalibur, next if some conditions are met, namely if the weapon exists in the weaponList and if it should be checked out to the person, who's making the request, then the invisible removeWeapon method deletes and retrieves the object from the invisible, closed up weaponList, weaponList returns that object to the removeWeapon function scope, then of course, removeWeapon will return that object for use to the scope of makeWeaponRequest and then the ARMORY namespace can decide what to do with Excalibur.
Global Imports
Welcome back, hope you enjoyed working with Anonymous Closures and now we're on to Section three, discussing Global Imports. So our current module seems to only need local variables, right, but if we look a little closer in one of these methods, we might find that a global variable is involved in one of them. Let's say that there was some global variable called wartime and it currently is set to true, which means the kingdom is at war, it turns out, inside of our makeWeaponRequest function, if it's wartime, we want to let civilians have weaponry to protect themselves, so our makeWeaponRequest function checks to see if war exists and if so, we'll let both knights and civilians have weaponry. First thing that happens is that the local scope of the namespace would be checked to see if wartime existed anywhere inside of that namespace and then if that namespace happened to be nested, we would go into that scope and check that scope to see if it's there, all the way up to the global scope. Now standard global use in a module pattern can cause two problems, the first is that when non-local variables are referenced inside of a module, the entire length of the scope chain is checked for that variable, first in this case for wartime, the local scope of the namespace would be checked, it'd look around the Armory, see if the wartime is there, it's not, and then if that namespace happened to be nested, then the outer namespace would be checked too and so on and so on and so on, until we've reached the global scope, now that search is going to happen every time wartime is encountered throughout the entire module, that's a very expensive process, if there is any sort of namespace depth or multiple references across the module. Problem number two is that lengthy namespaces mean that global variables can possibly have unclear scope, leading to code that is really tough to manage, developer gets into your file here to maintain your Armory module, sees wartime, this file is very long, by the way, so is the global file, doesn't know where wartime is coming from or what changes he can make to this particular file, it's really important for developers, who are maintaining your code to be able to place the source of your variables data, you don't want them to have to look through tons of code just to figure out where the data came from or what's worse, they may actually make terrible changes to data they think is local, so for clearer, faster globals in your modules, we want you to use global imports. Now, while devs may still need to review code and who doesn't, we all need to review code constantly, importing globals though creates much faster, local variables, that are also more clear in source. The first way we want to incorporate a global import is to add a parameter to the wrapper immediately-invoked function, here you can see we're passing in the war parameter, now we've got one parameter here, but you can create just as many parameters as globals there are, that you're importing, so since we're importing this parameter, war, we're going to need every place that we make reference to that global to change its name to the parameter, here you can see in our if statement, we've replaced wartime with war and here's where the magic happens for global imports, we're going to use our calling parentheses on our immediately-invoked function expression to actually pass in the global, that we want to become war and which one is that? Of course it is wartime, so now we have passed wartime in to our immediately-invoked function expression, wartime becomes war as a parameter and war gets used throughout the entire scope, yay imports. As a result of importing too, the variable that you need from the external scope gets closed up as a local value, it's just another piece of data boxed up in the closure. Cool little bonus about that is that the functions parameter creates this modifiable value inside the local scope of your namespace, that's pretty cool and the global value that you passed in stays protected, if it needs to be.
Augmentation
In this Section, we'll be talking about how to augment your modules. So yeah, modules often need to have additions to their existing properties, if you've ever worked in some large code base of documents, you're going to know the value of splitting functionality between many files. So here in our armory.js file is all that code that we built in the last two sessions, where the Armory module is, over here, we'll have globalkingdom.js, where all of the behavior globally for the kingdom is kept and there you can see our global variable, wartime with the true value, signaling we are at war. Now providing extra properties for existing modules can be done through a process called augmentation, in a separate file, we'll keep a function, which will add values or functionality to our existing Armory, here we have the warchest.js file, that's going to be our augmenter file, it's going to add functionality to the Armory in the event of war. Now augmentation is almost done like a recreation of the existing namespace, you can see here that we're going to be using the same sort of immediately-invoked function expression, that's going to return something to the ARMORY existing global namespace, that's why there's no var keyword on that ARMORY variable. Inside of our function now, we're going to pass the old namespace, right, and since it is our old namespace and existing as a global, we're going to go ahead and need to use our import knowledge and we'll import that old namespace as a local, in order to make some modifications to a temporary object, that it creates. Of course, in order to augment our module and return a new module with all the old stuff in it, we're going to need to pass in the old module and there it is, ARMORY. Notice the result of this immediately-invoked function expression, that uses the old module will be eventually an object that gets returned and stored back in the old ARMORY namespace. So what's the stuff that we want to close up and add in here? Well, we've got some local variables here called oilBarrels, of which there are 1000, we've also got some catapults to add to our warchest, Stoneslinger, Rockrain and The Giant's Arm, we've also got a new method called assignCatapult, that's going to take in some regiment number and it's going to hook a regiment up with a sweet catapult and of course, some oil barrels to toss at some Orcs. Notice here that our public functionality, namely the assignCatapult method is being added as a property on the old namespace object, which is local to this function, so once we've added all of our new private values and all of our new public functionality on the existing object, then we'll return the modified module, because now oldNS has an extra public property as well as these new closures, oilBarrels and catapults. Now, augmentation is super cool, it's great, right, it adds functionality, whenever you need it and it's especially great for public functionality, but we want you to be aware of one thing and that's that previous private data from your old file and your old function, that you used to build your original namespace, all of that private closure data will not be accessible to any of your new properties in your new file, the augmented properties will have access to their new private state and all those public methods over here will also have access to the private data right here, but none of these public or private values will have access to the closed data from the previous file. Taking a look, remember that closures are always produced by the function itself and never the returned object, so if we build a new function expression in our warchest file, right, it's not going to recreate all those closure references back to the old function, that was made in the previous file, very important to note, that means that any new properties are not going to have any access to all that old private data that we made, they will still be there, the earlier public properties that we had produced in the previous function, all those references to the closures will still be there for that, but any new properties will not have access to the old closed data, only to its new closed data. So the best practice here with regard to augmentation is to group your file contents around your needed data, any cross-file, private state build that you could manage won't even have the level of privacy of just a single closure and often it leads to hard-to-manage code, figuring out how the modules are augmenting each other or referencing each other, so the best practice is just to keep your file grouped around data that's related to each other and that need each other. You can see here though in our cool warchest.js file, that assignCatapult doesn't need any access to the old private data, so we don't have any broken references and our file is grouped very well for augmentation.
Course author
Jason Millhouse
Jason has been teaching since he was a kid and has racked up a bunch of Education degrees since then. A glutton for punishment, he's nearly finished with a Computer Science degree, too. He's built...
Course info
LevelAdvanced
Rating
My rating
Duration3h 14m
Released10 Jul 2014
Share course