What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Fixing Common JavaScript Bugs
by Elijah Manor
In this course we will examine common bugs that are accidentally introduced when developing with JavaScript.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Statement Bugs
Course Introduction
Hello, this is Elijah Manor, and this course is called Fixing Common JavaScript Bugs. The intent of this course is to learn JavaScript better, however, by looking at it a little bit differently. Instead of teaching you concepts up front, instead what we're going to do is take a look at some code that has a problem with it, either one that you've already had or that you might run into in the future. Then we'll identify this bug, explain what's really going on under the covers, and then look at various ways to resolve the issue. Instead of just showing you how to fix a problem, it's good for you to know why it's a problem so that you can protect yourselves in the future from either having the same issue or one that's related to it. As always, feel free to contact me on my blog at elijahmanor.com or on Twitter @elijahmanor. Now I'm assuming that you have some JavaScript knowledge already. This course doesn't start from scratch so if you need a primer, then I suggest you start with one of these courses, either JavaScript Fundamentals by Liam McLennan or JavaScript From Scratch by Jesse Liberty. You could still get value from this course if you don't have a background in JavaScript, or if it's been a while since you've written it, but there may be some concepts that I'm assuming that you already know. If you're fine with that or if you already have a foundational knowledge of JavaScript, then come right along and let's get started. One of the tricky things about this course is that I try not to clue you in on exactly what I'm trying to teach you up front. That might sound a little silly, but I don't want to give away the bug in each code snippet before it's time to uncover it. I want to see if you can spot the bug before we expose it together and then unpack it. So there are five main modules in this course. We'll first start with common bugs related to statements, then move to functions, expressions and operators, values, variables, and literals, and then objects.
Introduction
For the rest of this module we'll focus on bugs that relate to statements. So, let's get started.
Missing Mark Bug
So here's our first bug called the missing mark bug. What we have here is a function named getNames. Inside we're declaring two variables, a length and a names string. Then we have an array of strings, John, Susan, and Joe, and we're looping over them and incrementing the length variable and concatenating each item to the names string. Once our loop is done we'll return a custom object with two properties, the length and a string that has the concatenated names in it. Can you spot the bug? (Pausing to spot bug) As we attempt to expose this bug, what we'll notice if we run the code in the browser is that we get an exception thrown. It says Uncaught SyntaxError: Unexpected token :, which seems a little odd and confusing since the line it tells us is the problem does have a semicolon in it. If we take a step back and look at the code we might notice a couple of things that are a little peculiar. Two in particular. One, it seems that we've left out several semicolons throughout the code, but we tell ourselves that should be okay because semicolons are optional, right? And number two, our opening curly brace after the return is on a new line instead of on the same line like all the others. But again, we tell ourselves that should be okay, it shouldn't really matter. After all, we might be used to C# or Java. So what really is going on after all? Well as it turns out, JavaScript does need semicolons in order to parse the language, however, it is not guaranteed that there will be semicolons. So there's something called automatic semicolon insertion, also known as ASI that tries to assist with parsing if it's needed. Here are the rules for ASI. It's only applied when a new line or curly brace is followed by an invalid token. It's only applied when a new line comes before the -- or ++ token. It's only applied when a new line follows continue, break, return or a throw statement. And it's only applied if a semicolon is needed at the end of a file. With those rules in mind there are some exceptions when ASI will not run if they match one of these following rules. ASI will not be applied if it would result in an empty statement. An ASI will not be applied if its inside the head of a for statement. Phew, now that's a lot of rules and exceptions and some of those sound kind of confusing. So what does it actually mean for our code snippet? Well let's take a look and find out. So if we look at our code again and apply the automatic semicolon insertion rules, hopefully that will reveal any problems that we might have. If we apply the first rule, when a new line or a curly brace is followed by an invalid token, then ASI will add the following semicolons for us. And those all seem to make sense, its placing semicolons where we would have put them if we were following that style. However the third ASI rule, when a new line follows a continue, break, return or throw puts a semicolon at the end of the return statement. What? Now that's definitely not what we wanted, and that is a problem. Something else to notice is that ASI did not add a semicolon after our declaration of the names string. That turns out to be a problem too because that means JavaScript will think the following array code is actually part of the same declaration statement, which is not what we want. So since a semicolon was added after the return statement, this function will always return undefined at all times. Any code after the return statement will not be executed. As for the code above where ASI was not applied, well that's a problem too, because JavaScript sees that array notation that we meant to be an accessor off the empty string. It's essentially trying to grab the character at index Joe since it thought we were using the comma operator and not the comma separator, which we know makes no sense at all, and as a result we get undefined returned from it, which is totally not what we wanted. At this point you might be thinking, well this is too crazy, I'm just going to add semicolons everywhere, enough with this madness. Well, as it turns out there's a camp of JavaScript developers who prefer not using semicolons and letting ASI do its job while letting their code be semicolon-free. Well, for the most part. The end result could look much less cluttered since it's mostly void of semicolons. If you want to go this route then it turns out there's only two main rules you need to follow. One, don't put semicolons after your statements, which seems pretty obvious and easy to do. And two, if a statement starts with an opening hard bracket, opening parenthesis or a binary operator, then prepend your statement with a semicolon. An example of this style looks like the following. You'll notice that for the most part semicolons have been removed everywhere. Actually, there are no semicolons at the end of any of these statements. However there is a semicolon at the beginning of the render statement since it begins with an opening parenthesis. If we had left out the semicolon on the render statement, JavaScript would've thought that we were trying to invoke null with the home or new home argument, which is not what we wanted. So we can fix our previous code snippet with a semicolon-less technique by making two small changes. Number one, we need to prepend a semicolon before our array for each statement. This will let JavaScript know that we don't want this line to be part of the previous statement. And number two, we need to move our opening curly brace to the same line as the return, so that ASI doesn�t prematurely terminate our statement. And that's all we need to do to make this code functional. If you like this technique, you can still use the JSHint tool to validate the rest of your code, but you'll need to set the ASI option to true to keep it from warning you about your lack of semicolons. The other technique is to go ahead and add semicolons as they're expected, since they're technically required for parsing. This approach tries not to rely on ASI at all but rather tries to put semicolons only where they're required. Tools like JSHint or JSLint can let you know when these semicolons are expected. The following code snippet shows a small example using this approach. You'll see that every line that needs a semicolon has one. There isn't a semicolon at the end of the function statement because the specification doesn't expect one. So one last time, here's our code again with semicolons inserted so that automatic semicolon insertion won't take place. You'll see that most lines have a semicolon at the end and the opening curly brace is moved to the end of the return. And this code will perform and execute as intended. As with either approach, using tools like JSHint or JSLint can enforce these rules and help steer you in the right direction.
Missing Mark Bug: Demo
So here is the missing mark bug code inside of a jsFiddle, you can follow along here at the Fiddle URL. What we're going to do first is we're going to Ctrl + Shift + up arrow to create a little more room, then we're going to open up our dev tools, and run our code. What we'll see here is we're having an exception Uncaught SyntaxError: Unexpected token :. If we run JSHint, which is embedded in the Fiddle, we'll see lots of errors. Many of them are complaining about semicolons missing, but an interesting one here is, where the error occurs, is it's expecting an assignment or function call instead of an expression. If you remember the rules that we talked about with ASI, if it sees a return statement and then a line feed, JavaScript will actually put a semicolon right here, which is not what we wanted. Essentially all this code that's highlighted gets ignored. So the way to get around that is to not actually put your curly brace on a separate line, to actually put it on the same line, which doesn't feel like C# or Java, but that's kind of what you need to do if this is the type of code you want to write. So if I run JSHint again most of those errors will go away, so now we still have the missing semicolon, which is fine. There's still another problem, if we run our code again we'll see a different error, Uncaught TypeError: Cannot call method 'forEach' of undefined. So our forEach is here, and that's what it's complaining about. It's basically telling us that somehow this got evaluated to undefined, which makes no sense at all when you first look at it because hey, I'm declaring an array, it should have a forEach method if we're using a modern browser that has ECMAScript 5 on it, but for some reason it's thinking it's undefined. So if we think again of the ASI rules, there is no rule that says it needs to put a semicolon here. JavaScript actually thinks these two are connected, and it thinks that this array is not an array after all, it's actually an accessor. It's thinking that we want to grab this empty string and somehow grab one of its characters. And so now it's thinking that these commas are not comma separators inside of an array declaration, but it's thinking it's a comma operator. The way a comma operator works is it will evaluate each portion, so it will evaluate John, it will evaluate Susan, it will evaluate Joe, in the very last section of an or operator it will return. So essentially it's trying to take the string Joe index of an empty string, which is nonsensical and it will return undefined. And so since this returns undefined, if we try to call a method off undefined, ka-bam, we blow up, throw an exception, which is definitely not what we wanted. So the way to fix this is, I mentioned there are two rules of semicolon-less approach. One is to not put semicolons anywhere at the end of lines, so that's one rule. And the second rule is if you encounter a statement that begins with an opening hard bracket, an opening parenthesis or a binary operator, then we want to prepend a semicolon. So this is one of those rules because it's an opening hard bracket, so we'll prepend a semicolon, which essentially that will make sure that they're separated and JavaScript doesn't think those are combined. So now we can actually run our code, and we get what we expected, a length of 3, object, and the names as concatenated, John Susan Joe. But if we still run JSHint we still get all these errors that we have missing semicolons, so there's a feature in JSHint to say asi:true, basically meaning we're going to rely on the ASI feature, and so we're not going to actually put semicolons anywhere, and it's letting the tool know that, so now when we run it it's saying that everything's valid, good job, ya-da, ya-da. So now let's change this up and not rely on ASI at all. So to do that we will put a semicolon at the end of our declarations, we'll take off this prepended one, and add one at the end of the length, and the names concatenation, and the end of our forEach of our return, and our console.log. We'll rerun JSHint and it will tell us we're valid because we're actually putting the semicolons where the specification tells us we need to. If we actually put more semicolons than we need, so for example if we put a semicolon at the end of this function statement, JSHint will actually warn us and say hey, that's unnecessary, you don't need that, which is kind of nice. So now everything's valid, we could run our code, and it will work just fine, which is great. And so the tool, JSHint, will actually direct us in the appropriate way that we want to work, either using semicolons or not using semicolons. And we will fork this, which will give us a new URL with the appropriate answer, and you can use that for your reference.
Fresh Function Bug
For this fresh function bug, we have an array of people objects, then we're using the filter method to trim down the array entries to only those that have a birthday less than 1980. Then we're using that filtered result and calling the map method, which returns a new array of objects, each containing a name and age property. Can you spot the bug? (Pausing to spot bug) Now this one's a little tricky because the code works just fine in a modern browser. The error comes if we go back and use an older browser like IE8, which does not support ECMAScript 5. The filter and map methods were only introduced in ES 5 and IE9, which is also available in Chrome, Firefox, Opera, and Safari. So the problem here is that the filter and map methods aren't available in IE8, which is why the exception occurred. So that doesn't mean that we can't use these methods at all. These methods are very handy, and there are many others like them like forEach, every, some, indexOf, etc. We can either require a modern browser or we could polyfill this functionality. A polyfill is a library that simulates a native API, such as the ES5 array methods if they don't exist. Unfortunately this polyfill that I recommend was named Shim, which these days usually means something different. A shim has come to mean a library providing similar functionality, like a polyfill, but for one reason or another has a different API. Some popular shims to revive these methods are Underscore and Lo-Dash. However, these libraries are more than just a shim, they have lots of other handy methods that I personally find useful in my projects. So one way to solve this issue is to pull in the polyfill before we include our JavaScript. The great thing about a polyfill is that if we're using a modern web browser that supports these methods, then the polyfill doesn't have to do anything. The polyfill only kicks in to provide this behavior if the methods don't already exist. That allows the methods to work faster natively on the new browser and to fill in the gaps on older browsers. As another solution, we could have replaced the filter and the map methods with _.filter and _.map, but I'll leave that exercise up to you. As a side note, we could have used the reduce method to functionally get the same answer. Whatever you could do with filter and map, you could also do with reduce. Reduce takes a memo argument that's passed along to each iteration in the array. We initialize it to an empty array and then inside our call back function we only push to that array if the year is less than 1980, and as we push, we add a custom object with a name and age property. If there's no match, then we just return the previous memo array, which will then get passed along to the next item. By the time the reduce method finishes, we're returned to the memo array containing out the filtered and mapped result, and the answer will be exactly the same it would have been if we used filter and map together.
Fresh Function Bug: Demo
So what we have here is the code from the fresh function bug, we're including it in it a jsFiddle, you can follow along at this URL up at the top. What we're including is External Resources of moment.js, which is just a nice library to parse and manipulate dates. So let's press Ctrl + Shift + up arrow to give us some more room, and we'll open up our dev tools just to see what the output is. What we have here is some code. We have a people array with objects inside of it. Each object has an fname, lname, and bday property. And what we want to do is use the filter and map ECMAScript 5 methods. The filter method takes a callback function, which is invoked for each item in the array. And if we return something that's true, or truthy, then it says we want to keep that item in the array, and if we return something that's false, or falsey, then we're saying that we want to reject that item. And the end result is a new array with just the items that we said we wanted. In this case we're saying that we only want the objects that have a birthday that's less than 1980. So if we look at our objects here, this one's '79, and this one's '81 and '82. So we only want the ones less than '80, so we should have an array with just one item in it, which is John Smith. So once we have our new array, that returns our new array, then we're immediately going to call map off of it because map is one of the ECMAScript 5 methods off an array, so we could kind of chain those, kind of like jQuery. What map does is something a little different, but similar. So we still provided a function, which it will execute for each item in our array, but this time we're not saying that we want to keep it or reject it, we're saying that we want to kind of massage it or transform what it looks like. So for example before we had fname, lname, and bday, but here we're saying for each item we want a new object in our array that has a name and an age. The name will be a concatenated version of fname and lname, and the age we're going to ask moment.js to convert the date into a date object and convert it from the current date and see how many years it is. So the end result will be an array that has one item with name, John Smith, and age of 34, which that's great and it works just fine, so what's the problem? Well the problem is if we go way back into IE8 where ECMAScript 5 is not implemented So we're going to come over here to BrowserStack, this is just a nice way in a browser to kick up VMs of various versions of browsers, and we're going to paste in our URL, and we're going to actually append show on it. What that does for us is it will render only what's in the result pane, because some of this chrome around the edge doesn't work well in older versions of IE, so we just want to look what's actually rendered in the result. So we'll do that, we'll make sure we're picking IE. We could pick Windows 7 or Windows XP, either one will work just fine, all we care about is that it is IE8, and then we'll go ahead and say Start testing. So this will kick up the VM, and eventually it will show up here in our browser, which is nice. And we don't see much because we're console logging things, but if we look down here we do see an error. If we click on the error then it will tell us that the Object doesn't support this property or method, and what it's really saying is I don't know anything about filter. So if we come over to dev tools, we could poke around a little bit more. Let's go to Script, start our debugger, and sure enough, the line it's complaining about, or the big statement, is the one where we have filter and map. Now it's not actually telling us, but we could figure it out because we know that method doesn't exist. So there are a couple ways that we could fix this. Let's go over here and let's use a polyfill. So a polyfill, we kind of mentioned briefly, is a JavaScript file that simulates one of the native APIs that a browser has. So in this example we want to simulate that a filter and a map does exist, even though that it doesn't in older browsers. The way a polyfill works is if it's a newer browser that does know about filter or map, then it just won't do anything, but if it doesn't know about filter or map it will provide functionality that will look like it's working as the native browser does. So let's go and find one. We're going to go to cdnjs, which is just a nice repository of JavaScript files, and we're going to search for es5. So here's a shim that we're going to use. We'll copy this, we'll put it in our Fiddle. We'll save a new version of this, and so these resources get included before our custom code here. We'll update this to a new URL, come back over to our IE8 instance, we'll add show to it. And we don't get any errors, which is great. So if we come back over here and open our dev tools again, we'll see that now it's working. We have this console logging, one item in our array, name John Smith, and age of 34. So it looks like we're using ECMAScript 5 methods, but we're really not. The polyfill came in and recognized they didn't exist, and so it provided that functionality for us. So another way we could have solved this is to not use a polyfill, but to use a shim like underscore. And so let's pull in underscore. Now Underscore, the reason we call it a shim, is the API looks different from the native browser API. And you'll notice when I convert it that it does look different. So we'll remove our polyfill and add Underscore as a shim. There are a couple ways to do this, but we'll just use the simple way to begin with. We'll say _., and then we'll say filter, and then we have to pass the array that we care about, which is people. We'll pass the people as our first argument and the callback as the second. Everything else stays the same. And then we'll actually make a new statement saying _.map and people, people as our first argument, it's the array that we want to go over, and then the second argument is the callback that we want to actually handle the mapping of the fields. Let's run this again, make sure it works in our current browser. We'll update it, copy the URL, go back to IE8, let's add show. No errors, that's good, let's open our dev tools, and sure enough, we got the second item that it works, the second console log. So the other way we could have called this, if you really do like chaining, there is a way to do that in Underscore, but you have to call chain. It's a little strange, but it kind of makes sense. So we first tell it, tell Underscore the array that we want to start playing around with, and then once we've told it to start chaining, then we could call filter and we don't need to pass the array again, and so then we could chain that and actually say map, we could take off people. And the main trick here is when we're done, we actually have call value to actually get that internal array out, out of Underscore and say hey, now we're done with the chaining and giving my item. So if we run this, sure enough it still does work, so let's make a new version. Come back over to IE8, add show, there are no errors, and we'll open up our dev tools, and sure enough, we have another log that it worked. So these are multiple ways that you can still use the ECMAScript 5 features, but even in older browsers. Now if you don't care about IE6 or 7 or 8, and you know you know you're only going to use IE9 and above, then you don't have to worry about some of these things, but these are just for cross-browser compatibility. And just to let you know that you can still use these nice features, because even Underscore, it's more than just a shim for ES 5, there's tons of other nice things in there, and I would recommend you just pulling that in anyway, at least personally I find a lot of use case for it. Your mileage may vary, but I think it's a very handy library. And you also might consider Lo-Dash, there are some really nice features in there, and it's really fast and very modular.
Tumble Through Bug
For this tumble through bug, we have a getPrice function that will return whatever price we've defined for the fruit we've provided. Can you spot the bug? (Pausing to spot bug) The answer that we get is that passion fruit is only $0.50, which it should have been $1.50. This one may or may not have been easy for you to spot. If you see a switch statement, one of the first things you should look for is if all the break statements have been provided. If not, then you could possibly have a bug on your hands, unless it was intentional. In this case since there was no break after price = 1.5, it fell through to the pear case and set the price to 0.5. Since it has a break, the flow of execution removed to the return and we get the incorrect value. Thankfully JSHint will warn us about such things. Here's an error that we receive if we forget to provide a break inside our switch statement. Switch statements typically have a break statement after every case so that they don't conflict with each other. Since leaving out a break can cause a nasty bug, that's why there's a test case inside of JSHint to warn us when we've forgotten to include one. However, what if we meant to leave out a break? There may be times when you intentionally want a case to fall through multiple clauses. Thankfully there's a way to tell JSHint that you want to do this. All you need to do is provide a falls through comment where the break would have been, and JSHint won't complain. So in this case, the easiest way to fix the issue is just to add a break right after providing the price for passion fruit. And there you go, the code works just as intended. Another possible solution for this problem would be to not use the switch statement at all, but rather use an object to store the prices. What we'll do is have the keys of the object represent the fruit names and the values represent the price of each item. In addition we'll wrap our prices objects in an IIFE and make the data only accessible to the getPrice store method. The getPrice method can then access the prices object using the bracket notation to retrieve the corresponding price. This turns out to be a nice solution to the problem, and we don't have to worry about missing break statements. Before we move on, here is one last solution to the previous problem. Instead of using the switch statement or an object to store our values, why don't we let each fruit handle its own price inside of a function. Here we define a common prices object and then define a bunch of functions off that object that all know how to get their own price. The apple function knows that it's $1.25, and it will multiply itself by however many items are needed. There are several benefits of this technique. One, if you want to add another fruit, you don't have to modify existing code, all you have to do is add a new method. Two, each method controls its own behavior. For example, the passionfruit code has logic that its prices vary depending on what time of year it is. And three, you don't have to worry about those pesky break statements like you do with a switch statement.
Tumble Through Bug: Demo
So here we have the code for our tumble through bug. The intent is to have a function called getPrice and we could pass whatever fruit that we want to get the price of. In this case we're going to say that we want the price of passionfruit. We'll pass that in as the item, and we'll do a switch off the item. We'll case off that it's passionfruit, set its price to 1.5, but if we open up our dev tools what we'll notice is the answer is giving us $0.50 instead of $1.50, and that's because we forgot our break statement right here. So what happened is we set price to 1.5, but there was no break, so it fell through into the pear case, set price to 0.5, and then had a break and exited to return the price of 0.5, which is wrong. So the easiest way is just to add a break right here to fix this problem, but first let's run JSHint. It will actually identify that we have an issue and that we forgot the break statement before the case. So we could easily just say break here, rerun our code, and sure enough we get the right answer. But what if we really did want a fall through for some reason? Let's change up our code just a little bit and change all these to +=, and let's say there was a special deal where if you bought bananas, then you could get a passion fruit for free. So let's move our bananas down here to passionfruit, we'll take off the break, and then we will ask for bananas. So what should happen is we'll say hey, we want bananas, come down, get to the case of bananas, set its price to $0.75, and then we'll fall through to passionfruit because we're going to get a free passion fruit, and we'll increase the price an extra $1.50, and then we'll break and get out. So essentially we're getting a free passion fruit with a banana. And sure enough we've run our code, we $2.25, which is the addition of both of those together. But if we look at JSHint, it's still giving us a problem, it's saying that we forgot our break statement, but we did this on purpose. So in JSHint there is a special syntax, if you add a comment that says falls through, then that tells JSHint that you really meant to do this and it wasn't an accident. So if I JSHint again, it will actually say everything's valid. Instead of using the switch statement, there's another way we could have coded this. If we come over here, instead of using switch, which it's real easy to forget breaks, we could use an object instead. Also another problem with a switch statement is it gets really easy to put a lot of code inside of each case statement, and we want to keep this as succinct as possible. So what we could do instead is use an object, and for each key we can actually treat that as our fruit, and the value will be how much each item costs. So what we could do here is we could have an IIFE, because we want to have some private information, we'll store all of our fruit and prices, and then we'll have a public method called getPrice, which will access the object prices and then get at the particular value. And so it's using the bracket syntax to pass in a key, whatever we pass it, so passionfruit would be the key, and we're using that as an indexer to get at the passionfruit and get its value. So you may not know this, but in JavaScript I could've done this, passionfruit, to get the particular value using the dot notation, or I could use the bracket notation and get at the same information. And so that's essentially what we're trying to do here, but we're doing it dynamically because we're passing in the key as an item. And we'll multiply that by whatever quantity we want, so in this case we want 2 passionfruit, so it will go in, get us the price of passion fruit, 1.5, multiply it by 2, and then get us the answer. So that's a really nice alternative from having to use the switch statement. And again this is public, right here, this getPrice, because we're returning it right here, which leave the prices to be private. Another way we could have solved this is using functions instead, so each fruit will have its own function that knows how to get its own price. So here, for example, we're creating a new prices object, and for each fruit we'll have a function. So apple, for example, knows how to return its price and multiply it by however many items that you want. So if I pass in 1 number it will multiply 1.25 by 1. The cool thing about this is you could look at passionfruit. Now passionfruit is not just returning how much it costs, but it returns how much it costs based on some logic. So if it's a colder month then it might cost more, and if it's a month that's hotter or more in season, then it might be cheaper. This is also nice because if you add a new fruit, you're not actually modifying existing objects or switch statements, you're just adding new behavior and appending it to our object, and you don't have to worry about forgetting a break statement somewhere. So these are some alternate ways to solve the same problem.
Strictly Stray Bug
For this strictly stray bug, we have two JavaScript files, script1.js and script2.js. Can you spot the runtime exception that's thrown? Hint, it works fine in a development environment, but the exception only occurs when in production. (Pausing to spot bug) Well if you didn't guess it, it has something to do with combining and minifying your JavaScript, which is what we've been trained to do when going to production, right? Well there are other things like asynchronous script loading, source maps, but you get my point. The issue is that once we combine our two script files, that now the use strict directive gets applied to the whole combined file and not just that first file like it was originally intended. So what is strict mode anyway, and why do we even what it? Well, strict mode is something special that can be turned on in ECMAScript 5. Unfortunately IE9 does not support strict mode, although it does support the rest of ECMAScript 5. Thankfully strict mode is available in IE10 and can be used with Windows Store apps. As for other browsers, you're good to go there. So again, what does strict mode give us? Well, it helps prevent accidental global variables, which is great. It will give us an exception if we try to do silly things, like assign to a read-only property or delete something that should be undeletable. It also helps enforce us not to duplicate object keys or parameter names, something we shouldn't be doing anyway. It also makes the use of with an error and makes eval a little bit safer. There are more things you could do as well, but I think you get the point. It's super handy. The more feedback we could get up front about our problems in code, the better we could address them and continue building cool stuff. As a developer you should highly consider turning on strict mode, along with using a tool like JSHint, JSLint or the new ESLint to help with code quality. So how do you turn on strict mode? As you've already seen, you use the string use strict. Although it's just a string, it does mean something special to JavaScript. The reason it was chosen to be a string is so that it could be backwards compatible with older versions of JavaScript. So there are two ways you could apply strict mode. One is to a whole script file, as seen here, and the other is to only apply strict mode to a particular function, like here below. If we run JSHint against our code, in number one we'll get the following error, Use the function form of use strict. The reason for this is to exactly prevent the bug that we're getting where one file accidently sets use strict on another. So to fix our bug it's pretty easy. What we're going to do is wrap the contents of script1 in an IIFE, which is just a function that's immediately invoked. By adding a function wrapper, we can insert use strict inside of that IIFE in script1, which will only apply strict mode to that scope, which is good because script2 accidently is creating a global variable. The code for some reason might rely on this behavior, and if we said use strict then that would be considered an error. Either way, we should probably fix that code so it doesn't leak into the global namespace. However, it could be a third-party control that we don't have access to or we shouldn't be touching.
Parsing Parenthesis Bug
For this parsing parenthesis bug, we have an IIFE on top that's creating a store with the getPrice method, and then we have code below that's calling the getPrice method, passing in how many items it wants to purchase. Can you spot the bug? Here's a hint, there's a syntax exception thrown by JavaScript. (Pausing to spot bug) The exception is thrown around the IIFE at the bottom. As it turns out, JavaScript can't parse a function that's immediately invoked without having a little bit of help. JSHint actually helps us out here and tells us that we need to wrap the whole function in parens. As it turns out, to have an IIFE we can actually code it in a couple of different ways. The first example won't work, as we've seen. The most common approach is to wrap it in parenthesis as we saw in the JSHint error. Another approach that you'll see some people use is to prepend a unary operator, such as a bang, for example. This is enough for JavaScript to proceed with parsing, and it will not adversely affect your code. However for consistency, it's still considered best practice by many to use the parens instead. As it turns out, we don't technically need an extra set of parens around the code above, because it isn't a function statement like the previous slide, it's a function expression. However, it's not consistent, so JSHint encourages us to wrap the IIFE in parens to help the reader of the function know that something special's happening. It's essentially an indicator that this function's going to be invoked immediately. If the wrapper parens weren't there and the function was long, then the developer might not realize what was going on. So in order to fix our code and also make it easier to understand, we'll wrap both of the IIFEs with an extra set of parens. Minor changes can make a world of difference.
Evil Eval Bug
For this evil eval bug, we have a safe object containing the secret combination, and an open method that we'll use to expose from our IIFE. If the combination matches the safe we're trying to open, then we'll get a message saying it was opened, otherwise it will say incorrect combination. Can you spot the bug? (Pausing to spot bug) Okay, the title of the bug kind of gave away what was wrong with the code, but do you realize what kind of bad things can happen because the eval function? Well let's take a look at some of the fun things we could do. Here we have a call to the open method, passing in underscore, just because we really don't care what the safe is. Then we're going to put a semicolon to finish that statement. Then we'll provide some additional code where we could do whatever we want. In this case we're going to console.log the combinations for all the safes, the end result is that we get all the combinations listed in our console. Now we don't get into the safe with this attempt, but since we now know all the combinations, we can easily try again. Another fun thing we could do is the following. We're calling open and instead of asking for a safe combination, we're going to set the safe combination to something arbitrary like 999, and then we're going to request to open that same safe with our new combination of 999. And bam, we have just opened our safe. Thank you eval. Okay, okay, you probably knew that eval was dangerous in some cases. It's usually harmful when the user has control of what gets evaled. If you as the developer has control over what's evaled, then it's not so bad after all. You may want to read an interesting blog post by Nicholas Zakas called, Eval() Isn't Evil, Just Misunderstood, to learn more about this topic. But anyway, the point is if you find yourself wanting to use evaluation, then first ask yourself if there's a better way. There just very well may be something that you could do that's cleaner without having to use eval. Think of a JavaScript developer that you respect, and ask them. Thankfully, there is a warning by JSHint that will tell you that what you're going to do is harmful, and in this case it is. There's another way we could solve this problem. Instead of using eval, we could use the bracket notation off the combination object to dynamically access one of its properties. This is a little different than other languages like C# and Java, but it's a very common thing you could do in JavaScript. So the fix to our bug is to use the bracket notation to access the safe combination instead of using the eval function, and now we don't have all of these strange security issues.
Evil Eval Bug: Demo
So what we have here is a jsFiddle with the evil eval bug code inside of it, and we're going to go up to this URL, which you're welcome to join me, and we're going to append show, which will show us only the result pane, the bottom right pane, which will be blank, so we'll want to open up our dev tools, look at the Sources tab, take a look at our code, and press Escape which will bring up the mini-console. And now we're going to take a look at this in a little more detail. So here we have an IIFE, we have a function that's immediately invoked at the bottom, we're returning the things that we want to be publicly exposed, and so in this case we want an open method. Anything left is private, so our combinations object here has some private information of the safes and their combinations. So the main safe has a combination of 12345, and the fire safe has a combination of 67890. So what we'll want to do is grab this safe, which is returned from the IIFE, and call open. We'll pass in the safe that we want to open, which is main, and a password that we want to try to open it with. So main will be passed as type, so it'll be combinations.main, which will be evaluated, which we'll come in here to our combinations object, look into main, and give us 12345 as the password. That will be set back to the combination variable and compared to the attempt that we passed in. And if it's a match, then we're going to say the safe is opened, and if they're not a match, we'll say it's incorrect. So if we come in here and say safe.open, pass in main, and then 12345, then we have opened our safe. If we do that again and type in something that's wrong, it'll say it's incorrect. And again we could go and open up our other safe, 67890, and call it the fire safe, and sure enough, we open that, and if we had something bogus then that's incorrect. So at surface value it seems like everything is behaving just like we want. So let's come in here and do something a little sneaky. We will come in here and think like a hacker. So let's say we don't know what safes are there or what combinations, so we're just going to make something up. We'll say makeup. So makeup would go in as combinations.makeup, which doesn't exist and we'd get undefined, and that wouldn't really help us any. But what if we put a semicolon in? That essentially means we're done with our statement, and then we could start writing other code. So let's say console.log, and let's say we knew a little bit about the code, and we knew there was a combinations in there somewhere, which is the private information that we shouldn't have access to. Now it doesn't really matter what password we're going to pick because it just doesn't really matter at all, so we'll put something bogus in here. But if we enter, now we didn't get in, we didn't get the correct information, but we did get all the private stuff. So now we know what all the safes are and we know what all the combinations are. So then we could come back in and put in an appropriate combination, and then we get in. But let's say we didn't know that there was some private information called combinations, we could try something else. So let's go in here and let's say we did know there was a safe called main, but let's hack into it, let's force our way into it. So what we're going to do is instead of just passing main, which would resolve combinations.main, and that returns a value, let's actually treat this as an assignment. So what we're going to say is main=, and then we'll make up some value, 123. And what that will do is when it comes back in here it will say combinations.main= 123, and so it's doing an assignment. So that's a little tricky. So now that we've just reassigned the combination for the main safe, and since we did that when we pass in our combination we can match it up to whatever we just set it to, and voila, we just hacked our way into our safe. Now obviously this is pretty trivial and contrived, but let's go ahead and fix this so that we don't have the same problems. So we'll go back over here, take off show, and it's actually really easy to do. And I've made this mistake before where I used eval and was like oh, well I want to be dynamic and do all this fancy stuff. As it turned out I didn't have to do that. So all we really want to do is we want to grab something off of combinations. And so what we could do is use the bracket notation, and it does exactly what we want it to do. So there's several ways to access a property off of an object. One, we could say combinations.main using the dot notation. That works just fine, and that's the way probably we're used if we're used to C# and Java. But we could also access it using the bracket notation, so I could say combinations, open bracket, main as the string, and close bracket. So what we're going to do is we're going to use that idea, but do it a little more dynamically. We're going to pass in the type, use the square brackets, and that will get us the value. And so this will only give us values within this object, it's not just going to run arbitrary code, which is nice because that's not what we want. So we're going to update this, and we'll go to show, open up our console again, sure enough it opened it. Let's try one of our hacks where we're trying to force our way in. Well, we couldn't get in there. And let's try our console.log. No. So now I can't sneak my way in and run arbitrary code anymore. So anyway, I hope this helped to show you a little bit why eval can be dangerous. It's mostly dangerous if you're evaling code that a user inputs or an API evaluates. If as a developer in your code you have control over what you're evaling, there are use cases for that, but usually if you see eval you need to think long and hard, do I really need this, and maybe even ask someone that you trust and respect to see if maybe there's a better way to do it.
Fickle Figure Bug
For this fickle figure bug, we have some code that will wait for the DOM to be ready, and then we have a little jQuery to initialize our input fields with a jQuery UI datepicker. Can you spot a bug? (Pausing to spot bug) We have to go all the way back to IE7 to see the error in this one. IE7 complains about the trailing comma for our last key value pair in the object literal. This is not a problem with newer browsers, so this might not mean much to you, but for all the other developers who have to support IE6 and IE7, you need to think about this. So why does this even happen? Well, it's a very common thing to try out different options in a jQuery plugin. For example, I might want to quickly see what this widget looks like with the number of months turned on and off, but as soon as I comment out the last property, I get into the same issue that I had before in that now I have a trailing comma on the showWeek: true. Sure I could go and fix this, but often times it's forgotten. Some developers have gotten to the point where they've adopted the comma-first technique to counter this issue, so they could quickly see which commas have been provided. Whatever you do, it's important to know what's acceptable across various browser versions. In this case we care about Internet Explorer 7, 8, and 9. The issue here is that trailing commas both in object literals and also in arrays are errors in IE7, and that's why our previous code was broken. If we move to IE8, then things get a little bit better and neither of these cases are errors, but the array will have one more entry than you probably thought because of the extra comma. You might think that it only should have three items, but it really has four. IE8 added an extra entry with a value of undefined because of the extra comma. Thankfully ECMAScript 5 has made trailing commas legal in both cases, and no longer we get strange behavior with the array, so we should only get the items we meant to include. So with trailing commas, you're safe in IE9 and above. The fix to this bug is really easy, all you have to do is remove the trailing comma on the last property, that is if you care about IE7, which you may not need to on your project. Thankfully JSHint can help you out here as well if you have the ES 3 option turned on, and it will mention that you have an extra comma and that it breaks in older versions of IE. One more important thing to note before moving on, even if you don't care about trailing commas. Let's say for example, you only have to support IE8 and above, you will still need to be careful about trailing commas in your JSON. If you have a library generating your JSON, then you probably should be fine. However, if you're manually building your JSON in code or if you've hardcoded JSON anywhere in your code, then you might want to double-check to make sure you don't have any trailing commas after the last key value pair, because that's going to break JSON.parse.
Summary
So that's it for this Statements module. We had talked about being intentional with your semicolon placement, whether you choose to add semicolons or not, there are rules for you to follow one way or the other. My personal preference is to add semicolons as the specification says, and not to rely on ASI. If you want to use the new ES 5 methods that are available, then more power to you, but you must keep in mind cross-browser support. You could provide a polyfill for older browsers, or instead use a shim like Underscore or Lo-Dash. Be careful when using the switch statement, forgetting to add appropriate break statements is a common bug. Make sure to add the falls through comment if that's what you intend, or think about some of the other solutions we talked about as an alternative approach. Be careful when using strict mode. It's highly encouraged that you use it, but make sure you apply it to a function and not the whole file. If you are using IIFEs, then consider wrapping them in parens. In some cases they're needed, or something like them, and in other cases they're just for clarity to the developer. The eval function can be dangerous, so beware. Oftentimes there's a better way to solve the problem other than using eval. If you aren't sure, just ask a developer that you trust. And IE7 and IE8 don't like trailing commas with object literals and arrays. There are some gotchas there, so be careful.
Expression and Operator Bugs
Introduction
Hello, this is Elijah Manor, and in this module we're going to look at some common bugs when dealing with expressions and operators in JavaScript. Along the way we'll uncover some foundational concepts in JavaScript to help you become a more efficient front-end developer.
Crude Computation Bug
In this crude computation bug, we have a simple for loop and we're incrementing the i variable by 0.1 and console logging Hello until we reach an index of 1.0, at which point we exit the loop. Do you know what will be logged in the console? Can you spot the bug? (Pausing to spot bug) So the bug may or may not have been obvious. For one thing, you probably aren't in the habit of writing your for loops like that. Well, the output from the console might surprise you if you're new to JavaScript or haven't done much arithmetic with the language. What you'll notice is that the precision of the numbers get off by just a little bit on occasion, and in our case that lack of precision actually causes an infinite loop because we're checking for a value of 1.0 in order to exit the loop. But the closest the number the i variable got was 0.9999, etc which is not 1.0. So what in the world is going on anyway? Why all this madness? Well it turns out that JavaScript only has 1 number type, and it's the IEEE 754 double-precision floating point. The number is 64-bits, where 1 bit is for the sign of the number, 11 bits represent the exponent of the number, and the remaining 52 bits represent the fraction portion of the number. The great thing about this type of number is that you could represent a wide range of values, but the downside is that some of the precision can be lost in the process. For example, if you try to add 0.1 with 0.2, you'd get 0.3000004. And if you tried to log 9999999, then you'd get a number that was 1 larger. If you try to add up an array of numbers that represents money, then the end result may not be exactly what you intended. In this case our result is 10.0800000002. And when it comes to money, usually you want things to be exact. So one solution to this problem when dealing with money in particular is to convert all values to whole cents, do all manipulations with cents, and when you're done, convert the cents back into dollars. I know that isn't optimal, but you don't run into the weird precision issues this way. So in this case, to fix the infinite loop, we're going to first check if the index is less than 1 instead of checking when it's exactly 1. That will resolve one of our issues, the infinite loop, but we still have the issue where our index values are sometimes off a little bit. So to address that issue, we'll use the technique we talked about earlier by doing our arithmetic with whole numbers, and then convert to the fraction when we need it. Here for example, we're incrementing whole numbers and inside the console log we divide by 10 to get our message. And you'll see that now the decimals appear to look just fine. Multiplying and dividing as I showed in the last example might be a little cumbersome. As an alternative, you could use one of the following math libraries instead, Big.js or BigNumber.js. They're actually sister projects and their goal is to facilitate arbitrary precision, decimal, and non-decimal arithmetic, so you won't get into the same situations that we showed in the last several slides. As a review, if we use the native number type and subtracted 0.1 from 0.3, that would give us 0.199999998, but if we use the BigNumber, we could wrap the 0.3 value, call the minus method to subtract 0.1, and that would give us 0.2, which is more of what we expected. Now there is a little extra overhead as we have to interface with the API, and overall the performance won't be as good as the native implementation, but it can help you if precision is important to you.
Mistaken Mold Bug
For the mistaken mold bug, we have a function called getResource that once the resource has been retrieved via AJAX, will invoke the callback function or array of functions that was provided. At the bottom we have two functions, cb1 and cb2, that we'll be using as our callback functions. And then we call getResource twice, both times to get a data.json resource. The first call to getResource we want cb1 to be invoked when the response is available. In the second call to getResource we want both cb1 and cb2 to be invoked when the response is available. Do you know what will be logged in the console? Can you spot the bug? (Pausing to spot bug) So this bug might have been hard to spot unless you know the type of operator pretty well. What we end up getting is a successful response when calling getResource with the function as the callback, but we end up getting the following exception when trying to pass an array of callbacks, Uncaught TypeError: object is not a function. The reason for the error is that the type of an array is not the string array. And what is it you ask? Well let's find out. Typeof is a great operator and very helpful, but in certain cases it doesn't yield the result that you would like. For example, on the left it does a great job with boolean, number, string, function, undefined, and object, but on the right typeof isn't helpful at all, it returns object for null, error, arrays, dates, and regular expressions. Thankfully there are some methods that could help us out a little bit. For example, if you're already using jQuery, there's a type utility method that brings some sanity back to its results. So for example, on the previous page that returned object, now we can return null, error, array, date, and regex as we probably expected. If you aren't using jQuery, or if you already have Underscore or Lo-Dash, then you could also use some of these helpful methods: isNull, isArray, isDate, and isRegEx. However, there's not a method to test for an error object. In addition, Underscore also has some other helpful methods, such as to check for an empty object if an object is the argument's implicit parameter, if a number is finite, and to test for not a number. So we can easily fix our broken code by using one of those helper methods. In this case we'll use the _.isArray method to check if the parameter is an array or not, instead of using typeof. And now we get the output we're looking for, yay.
Mistaken Mold Bug: Demo
So this is our mistaken mold bug, and here we're using Plunker, and you're welcome to follow along at this URL. What we're going to do is look at our HTML page. We're just pulling in the request library, which is our micro-library for doing AJAX, we have our custom JavaScript, and then we're pulling in the Underscore in jQuery, which we'll look into in just a minute. So if we take a look at our code we called getResource twice, we'll look at the code in a minute, but we essentially want to retrieve some data from the server, and then when the data is retrieved we want to call a callback with that data. In the second example it's overloaded if I pass an array as the second argument, then I actually want it to call both functions and pass the data to both of them. So I could either pass one function or an array of functions. So let's go into our code, and here it's getResource, I tell it what URL I want to go to, so data.json, and I either give it a function or an array of functions. So I hit the request. When the data comes back I'll console.log to make sure I got data from the server, and then it checks to see if callbacks is an array or not. If it's an array, it's supposed to loop over them and call each callback separately passing the response. Otherwise it will assume it was just one function and just invoke that with the response. If we run our code, what we'll notice is we get, sure enough we do get a response, and sure enough it did call the callback. But in the second case where we passed the array, it got the response from the server, but then it blew up, and why it blew up is because when you do a type of callback and it happens to be an array, we don't actually get the array string, it gives you an object. So if I did typeof, and I asked it what the type of array is, it actually tells me object and not array, which is what I wanted. So we need somehow to fix this. There are a couple ways we're going to look at fixing this. One is using jQuery's type utility method. If we pass an array to that, it'll actually give us the string array, which is nice. We'll also look at using Underscore. There's an isArray method, which we could pass an array in and it will actually give us true or false. So let's go in here and change this to jQuery's type, and then we'll wrap the callbacks, and now it works just fine. We get the data from the server, it will callback that particular function, and then we get the data from the server again, and then it actually loops through the array, calling each callback separately. And we could also change this to _.isArray, change this up a little bit, and that will work just fine too. Here we get the response from the server, it'll do the callback. Now they're a little out of order because they're async and I'm not enforcing an order, but they all work. If it's an array it will loop over them, if it's just a function it will invoke that one. And there you go. Now these methods are a lot more helpful than just this particular scenario. Underscore, for example, has tons of other methods like map and reduce and things like that that ECMAScript 5 has, not necessarily older browsers. Now obviously these libraries are a lot more helpful than this particular scenario, but this is where they could be very helpful in this particular case. I typically have Underscore on most all of my web projects just because there are so many helpful utility methods that help me get my job done. However, if you don't have Underscore on your project and you're just using jQuery, then that makes a lot of sense to use the type utility method.
Twisted Truth Bug
In this twisted truth bug, we have a function called sell. In the function it tests to see if the price was provided. If a price was provided, then we'll check to see if it is 0, and if so it will be converted to the price Free. Otherwise, it will prepend a dollar sign and format the price. If a price was not provided, then a Please provide a price message will be displayed. At the bottom, we're selling New Things for $0.50, Old Things for $0.00, so it's free, and we're selling Whatchamacallits, but we didn't provide a price. Do you know what the output will be? Can you spot the bug? (Pausing to spot bug) Did you spot anything fishy? Well here's the output of the code snippet. The first message looks correct, and the last message looks correct too, but the second message does not. Instead of saying Selling old things for free, it says Please provide a price. What? So this is where the concept of truthy and falsey becomes important, and it's quite different from other languages that you might know such as C# and Java. Unlike many languages where there's only one value for true or false, in JavaScript there are several. The easiest way to remember this is just to memorize the falsey values, and then everything else is truthy. So the seven falsey values are undefined, null, false, +0, -0, not a number, and empty string. Some of those might be surprising to you, but they are what they are, falsey. And everything else, well, they're truthy. So for example, the following are all falsey, false, 0, null, empty string, etc. And the following are truthy, true, the number 5, the string John, an object, an array, a regular expression, and really anything else that isn't one of our 7 falsey values. The easiest thing to do is just to memorize the seven falsey values. Life will become much easier in JavaScript once you do that. So the problem with our previous code is that we were just checking if price was truthy, but really that was checking if price was not all of the seven various falsey values. So when the price was 0, it was falsey even though we provided the value, so it went to the else branch and logged that we needed to provide it. So let's be a little more exact in our price check and we'll compare it against undefined, which is the value a parameter gets if you don't provide it to a function. And that fixes our problem just fine. Now our second console.log says Selling Old Things for Free instead of thinking we did provide a price at all.
Twisted Truth Bug: Demo
So this is the code for the twisted truth bug, you're welcome to follow along at the jsFiddle above. But what we have here is a sell function, the way we're going to call it is we're going to tell it what item we want to sell, and then we're going to give it a price. So here we'll say New Things is $0.50, Old Things are $0.00, which should be free, and Whatchamacallits we didn't provide a price, so we want it to actually tell us, hey, you need to provide a price. If we look at the output down here, the first on looks good, we're selling New Things for $0.50, the last one looks good, we're actually telling them they need to provide a price, but the middle one doesn't look like what we expected. We kind of expected it to say Selling Old Things for Free. So let's take a look and walk through this and see what we meant to do, and then we'll talk about why it's not doing it. So the first one we provided New Things as the item at $0.50 as the price. We come in, we look at the price, we see hey, did they provide one? Yes they did. We'll come into this ternary operator, does it equal to 0? Well, no it doesn't. So we're going to prepend a dollar sign and format the price, and then we'll say Selling New Things for $0.50. And that works. Let's skip to the last one for a second, Whatchamacallit. We come in here, oh, there is no price and so it goes to the else statement and says Please provide a price. Now the middle one where we say Old Things and pass in 0, what we want it to do is come in here, look at price, oh, yes, we provided price, yes it does equal 0, but let's change it to free. So we'll say Selling Old Things for Free, but it doesn't do that. Somehow this expression is falsey and it gets into the else statement. So why is that? And it's the concept of truthy and falsey values, and we just need to memorize these seven falsey values. We have false, obviously as a falsey value. Plus 0 is a falsey value, and what we're going to do to convert this to a boolean to let us know it's really false, is we're going to not it twice. The first not actually coverts it to a boolean, but since I said not it flips the bit. So if I really want the original value, I have to flip it again. It's a little weird, but it works. So then we have -0, it's actually falsey as well, it's a little silly that we have to do both, but they're actually different values. Null is a falsey value, undefined is a falsey value, not a number is a falsey value, and finally, though this one kind of confuses some people, the empty string is falsey. So what was really happening, we said Old Things, we provided 0 because we're actually providing a price, but we came in, we were checking to see if they provided it, but actually 0 was falsey, and so it went into the else statement. What we really wanted to test is that they provided anything at all. So what happens in functions, if we don't provide an argument that there's a matching parameter, then the parameter's default value is undefined. So we could use that to our advantage here and say, as long as price is not equal to undefined, then we'll come in here and assume that they provided a price, otherwise then say, hey, you need to provide a price. Now this will work and everything's great, Selling Old Things for Free, and technically someone could have done this and actually passed an undefined and that would work as well, but still they haven't provided a price so it's still a valid message. So the important thing here is to remember the seven values of falsiness because everything else is truthy. So if I said, if I wondered if a 5 was truthy or falsey, well it's true because it's not 1 of those 7. If I wondered if the string John was truthy or falsey, then obviously it's true because it's not one of the seven. You get the point, so objects, anything in here, this would be truthy, because it's not one of our seven. Arrays are truthy, because again, it's not one of our seven. So really anything that's not one of those seven is truthy. It's a very valuable concept to know because a lot of JavaScript kind of relies on this concept, and so it's best just to kind of memorize it.
Crafty Convert Bug
For our crafty convert bug, we have a bacon object with a slices property and a buy method where you could buy pieces of bacon. If you buy 0 pieces of bacon, then you get a message of WAT? If you pass true as the second parameter, then that means you want to cover the bacon with chocolate, then the slices parameter gets incremented by however many slices you purchased, and then a final console.log showing how many total slices of bacon were purchased overall. And then below we call the buy method several times, passing various parameters, some normal, and some quite odd. Do you know what will be logged in the console? Can you spot the bug? (Pausing to spot bug) So the first three calls to buy work as expected. When I purchase 0 strips of bacon, I get the, WAT? message along with 0 total slices of bacon. And if I purchase 5 strips of bacon, I get the message 5 total slices of bacon! And if I purchase 10 strips of bacon and pass true as the second argument, I get the message Adding Joy, and then 15 slices of bacon. However, things start to get a little strange for the last two calls to the buy method. When I call buy, passing an empty string as the first argument, and the string 1 as the second argument, I get WAT?. Adding Joy, and 15 total slices of bacon logged to the console. And to that I say what. That is truly strange, but as you'll see later we can make sense out of it. The final call to buy is even stranger. We're passing a string with an exclamation mark as the first argument, and an object with a toString method as the second argument. The result we get from this is Adding Joy to the console, and then 15! Total slices of bacon. And again, to that I say, what? Now that you've been thoroughly confused and blown away by this randomness, let's pull away the covers and see what exactly is going on. So before we start to dig deep into this, let's first talk about the Strict Equality Comparison Algorithm. You may or may not know this, but there is a triple equals you could use for comparisons. You'll find that many developers actually recommend you use this technique instead of the double equals, and you'll see why this is in the next couple of slides. But anyway, the triple equals checks to see if the type of the variables is the same when it's comparing them, and if it's not, then it evaluates to false. If the types are the same, then if they're both undefined it's true, if they're both null it's true, if they're both numbers and their values are the same it's true, if they're strings and they have the same characters it's true, if they're Booleans and have the same value it's true, and if they're both objects and refer to the same instance, then it is true. Otherwise if it doesn't match any of those rules, then it's false. These rules are predictable and should feel pretty familiar to other languages you might know, at least for the most part. However, things start to get a little more interesting if you start to use the Abstract Equality Comparison Algorithm, the double equals. If both types are the same, then the same rules apply that we discussed in the last slide, which are pretty straightforward. However, if the types are different, then things start to get a little more complicated. If the types are a number and a string, then the string gets converted to a number. We'll take a look at that algorithm on the next slide. If either of the types is a Boolean, then the other type is converted to a number. If one type is an object and the other type is a string or number, then the object will get converted to a primitive value. And finally, if none of these are a match, then false will be returned. These rules can be memorized, but you might start to appreciate why some style guidelines suggest you use the triple equals instead of the double equals. So several of the conversions from the previous page had a ToNumber conversion, this slide describes what that looks like. Most of these are straight forward, so that's good. ToNumber of undefined is not a number, which makes sense, null is 0, true is 1, false is 0, an empty string is 0, a string with a value is converted if it's in a number format, and an object is converted to a primitive, and then that's passed to ToNumber. The ToPrimitive process is to return the valueOf of the object if it's a primitive, otherwise call the toString method if it returns a primitive, otherwise throw an error. Before we actually go and exterminate the bug, let's go and talk about the additional operator for a second. Before anything happens, both the operands get converted to a primitive if they're not already. Then if either side of the additional operator is a string, then both sides will get toString'd and concatenated together. Otherwise, they'll both be toNumber'd and added together. So here we have a 4 and a 2, both numbers, and so they're just added together to make 6. Then the next example we have a string 4 and number 2, and since the 4 is a string, the 2 will get converted to string, and then they'll get concatenated together. And really the rest of the examples follow this same pattern. So hopefully all these make sense now, even if they didn't at first. So what we're going to do here is make three small changes. First we'll exit out of our function if the quantity variable is not a number type, and then instead of using the double equals we'll use the triple equals so there's no type coercion going on. By making these changes, it protects us from at least two cases falling through by accident, or ones like them. Now the output looks much more like what we would have expected. As I mentioned before, a lot of coding guidelines recommend using the triple equals for comparison. JSHint helps us out here as well and encourages us to use the triple equals. However, as most JSHint rules, you can turn them off if you'd rather not follow them. Before we move on, I wanted to show an alternate version of the previous fix. There are some JavaScript developers who view overuse of the triple equals and its counterpart, the not double equals, to be overkill and unnecessary if you know that both types are the same. So in this example, we use the double equals when we know the types on both sides of the operator are the same. And since they are the same type, they follow the same rules as the strict triple equals.
Crafty Convert Bug: Demo
Alright, so here we have the crafty convert bug, you can follow along at the jsFiddle above, but what we have here is a bacon object with a slices property and a buy method. We're going to use a little trick here that we're going to use the console.group, we'll give it a name, and then we'll give it the arguments that we're dealing with. And at the very end of our method we'll call groupEnd, passing the same name and arguments. So what that gives us is something kind of nice. If we look over here in our console we're just using Firebug Lite, it'll actually group our messages that are pertinent for this particular method. Otherwise, there'd just be a whole bunch of log messages and they'd run into each other and it's hard to differentiate where one begins and the other ends. So we'll just be using that nice trick. So essentially we have bacon and we want to buy it, and we want to keep track of how many items that we have. Our buy function you pass in the quantity that you want to buy, and then you pass it if you want to cover it with chocolate or not. The very first one we pass in 0, so we don't want to buy any bacon. It comes in here, and if it is 0, it says WAT? So if we look over here we'll see a message saying why did you even try to buy bacon if you're not going to? So it's kind of a silly thing to do. But eventually we're not covering it with chocolate, we're incrementing 0, which doesn't do anything, but eventually we're saying 0 slices of bacon were purchased, so 0 total slices of bacon. The second one's a little more interesting, we're actually buying something, 5. Since it's not 0 we're not going to get questioned like what am I doing, and we're not doing chocolate, so that's fine, we're just going to increment our slices and then we're going to print out that there's 5 total slices of bacon. And sure enough, we get one message, 5 total slices of bacon! The next one's a little more interesting. We're saying we want more bacon and we want it covered with chocolate. We come in here, quantity is not 0, so we won't see that message, but now chocolate is true, so we're going to add some joy. We're going to increment our slices so we should now be up to 15, 15 total slices of bacon! And sure enough, we're Adding Joy because there's chocolate, and there's 15 total slices of bacon! Now things start to get a little weird. We pass an empty string for our quantity, and a string with a 1 in it for our chocolate. If we look over here in our console, we're getting actually a lot of things in here, which is kind of confusing. It makes sense that it says 15 total slices of bacon because we didn't really add any, so it stays the same, but the other ones, why did those even show up? Well part of the reason behind here is there's the double equals, and what that does is if the types aren't the same on either side of the double equals, it will try to coerce and convert each side to kind of be the same, and then it does a comparison. So what happens here, we're passing an empty string, we're comparing it to a number. When you compare a string and a number, the string gets converted to a number. So what happens here is the empty string gets converted to a 0, which is equal to a 0. And so that's why we actually get into this if statement, and it says WAT? So then we'll have to look at the next item here. We have a string with a 1 in it and we compare that with a Boolean. So if you're comparing a Boolean to anything else, what happens is the Boolean gets converted to a number. So true gets converted to a 1. So now we have a number and a string. So the string gets converted to a number, and if you have a string, as long as it's actually a valid number inside of it, it'll get pulled out and converted to a number. So in this case we have a 1 equal to a 1, which is true, and now we are able to say console.log Adding Joy. So it's confusing, yes, there's a lot of conversions going on, but since we actually said double equals, that's what we get. If we come down further to our next example, we are passing in exclamation point for the quantity, and we're actually passing in object for the chocolate. So let's talk through this one. So we're passing in an exclamation point, eventually it'll say Adding Joy, and then we'll get this weird message, 15! total slices of bacon! So we'll come in here, quantity is an exclamation point, so what happens is that's a number and a string, so the number stays the same and the string gets converted to a number. Of course what's in this string is no way converted to a number, so that gets converted to not a number, which is not equal to 0, so that doesn't get in there, whereas the object comes in here as comparing against a Boolean, so what happens there is Boolean gets converted to a number, which is 1, and then chocolate gets passed through something called toPrimitive. And the way toPrimitive works is it will first call valueOf to try to abstract a value that's a primitive. Well, in this case it can't get anything. So the second one it goes to is it will call toString and see if it could get a primitive out of that. And we did actually provide a toString, so it will return a string of 1. And so now we have the number 1 compared to a string with 1, and so then the string will get converted to a number, and since there's a number inside the string, that's a valid number, it will get converted to a 1. So now we have a 1 equals to 1, which is why we're Adding Joy. A lot of weird stuff, but it's because we're using the double equals. We can make this a little less confusing by using the triple equals, which does not coerce types on each side. If they're different types, then it's false. So if we rerun this it will be a little bit better, it won't be perfect yet. So the first three ones we're fine with. It's the last two that we don't really want to do anything. We're fine with the, this buy one's actually fine, but it would be nice if it just didn't do anything. And this last one's a little confusing. What it does here is when we use the addition operator, if one of the items happens to be a string, then the number will be converted to a string as well, and so they'll concatenate and not actually add, and so that's why we get a 15!, those are actually strings being concatenated together. So let's go in here and double check that the quantity is a number. Quantity, and if it is a number then we want to continue, (Typing) and if it's not, then we'll just, we'll do a little formatting, if it's not then we'll just not run all that code, we'll go ahead and end our group, but that's it. So let's run this again. So here we go, we have the first three run just fine, but the last two we don't actually console.log anything, so they're just kind of no ops. So hopefully that makes a little more sense of some of the dangers of the double equals. Now again, you could memorize all these rules, and that's fine, and it's actually in a weird way kind of fun to know what's going on, but most of the best practices these days will encourage you to use the triple equals instead. Now you have some people who think it's a little overzealous to always say triple equals. So for example, if I knew this was a number and I came in here, and since 0 is obviously a number, and at this point I know quantity is a number because I just tested it, well it would be technically safe to use double equals to test this number against this number because they're the same type. And as we looked before, even when you use the double equals, if they're the same type, it obeys all the rules as if it were using the triple equals, so you're not having any danger here. Now however, chocolate, we don't really know what type it is. We're not checking it and we're testing it as a Boolean, so it might be a little dangerous to use the double equals, so it's better to use the triple in this case, unless we actually knew it was Boolean. So these are some gotchas, hopefully that makes a little more sense, and there you go.
Problematic Pause Bug
In this problematic pause bug, we have a max function that accepts n number of arguments, and it will loop over them and return the largest number that it found. Take a few seconds and see if you could figure out what will be logged to the console. Can you spot the bug in this piece of code? (Pausing to spot bug) So there may be several things I'm doing in this code snippet that you might not be familiar with, but we'll unpack that here in a few minutes. First let's check out what the output of this code is, and of course, we have a bug because we always do, right? Once the 1 is processed, it is identified as the max, then 3 comes along, which is the largest, and so forth, until hopefully we get a max of 9. But wait a minute, max's console.log is undefined, how can that be? Well let's take a look at the comma operator, which I was using in several places in the previous code snippet. The comma operator evaluates both sides of its operand, from left to right, and returns the value of the second. So the following piece of code evaluates single to 3, then evaluates double to 6, and then it returns 6, and assigns it to the wat variable. It's a pretty easy concept to follow, but it's important to know. So the main issue with the buggy code is that I had a comma after max and it was returning the arg variable from the max function since it was on the right of the comma operator. So if I remove the arg from the return statement, things start to work as expected. I'm still using the comma operator to store the length of the arguments when initializing the i variable, and in addition to checking if i is less than length, I'm also assigning the arguments at index I to the arg variable, which cleans up the code inside the for statement just a little bit. I removed the console.logs, but if you recall those were using the comma operator as well, so I could sneak in an extra statement where it didn't really belong. As a side note, you probably want to be careful with the comma operator, as it encourages you to write really terse and hard to read code. But if it makes sense or really cleans things up, then I think it's okay. As for most things, try to follow best practices unless you have a good reason. Use your best judgment and ask a friend too.
Ignored Invention Bug
In this ignored invention bug, we have a Cat constructor and we're creating two new cats, Fluffy and Midnight, and then we're logging them to the console via JSON.stringify. Can you spot the bug? Do you know what's really happening? (Pausing to spot bug) So Fluffy ends up logging to the console correctly, but Midnight logs out undefined, hmmm, that's unfortunate. But thankfully Midnight hasn't been lost completely, he could be found on the global window object. However, that's actually not cool at all. So what's going on exactly? Well, we forgot to include the new operator when calling the constructor to create Midnight. What does the new operator even do? Well, it creates the new object, sets its prototype to the constructors prototype, executes the constructor using the new object as the this context, and then returns the new object. So let's take a look at the following code and talk through what's happening. If we use the new operator along with the constructor, a new object will be created. Once we get inside the constructor, the this context will refer to the newly created object. However, if we tried to call our constructor without using the new operator, then no new object will be created, and then when we get inside the constructor, the this context will refer to the global object, which is the window object. This is bad because we're now appending things onto the window object that is global to everyone. Oh boy, as a result it is considered a best practice to uppercase your constructor function to communicate to other developers that something special needs to be done with this function. It's a constructor and it needs to be new'd up. If you're concerned about developers accidently calling your constructor without using the new operator, then you could add some extra code to help protect against that. Here in our constructor, we're checking if this is an instance of a person. If it isn't, that means it wasn't new'd up correctly, so we could manually new up a version of person, passing in the appropriate arguments, and that will make sure the this is a new person and not the window object. So in order to fix our code, all we needed to do is make sure we use new operator before creating our Midnight Cat, and all is well. And now we don't have any leaked items on our global window object. In addition, we added some code to our constructor to protect against someone not using new, just in case. And again, we have JSHint to the rescue, and it would've given us the following error in our previous buggy code, Missing new prefix when invoking a constructor.
Ignored Invention Bug: Demo
So what we have here is our ignored invention bug, we're working in a jsFiddle, and you're welcome to follow along at the URL above. Here on the right we're using Firebug Lite just to look at our console, and in our left is our code. We have a Cat constructor with name, breed, and color, and we're creating new instances of Fluffy and Midnight, and then we're going to log them out, and we're also going to log out the window because there happens to be something going wrong here and we want to see it. So here we're newing up fluffy, Fluffy, Ragamuffin, White. If we look in our console, sure enough, here's Fluffy. And then we're newing up midnight, Midnight, Bombay, Black. But when we console.log it it's undefined, so where did it go? Well if you look closely we actually didn't put the word new here in front of the cat. So what happens, it actually didn't create a new object, but it still went in to the constructor, but what was this? This was the global object, which is the window. So what was really happening is it was appending name, breed, and color off of the window object. So if we come down here in console.log, window.name, window.breed, window.color, and look in our console, then it shows up. So there's a couple ways we could fix this. One is just to actually provide the new keyword right here and then update our code, and sure enough, things work just fine, now we have both objects. But since someone forgot to put new, maybe they would forget later, so let's take a look at a different technique that we could use. We'll come up here and inside of our constructor the first thing that we'll do is we'll double check that whatever this is is an instanceof the Cat that we want. And if it's not, if it's not an instanceof the Cat, then what we'll want to do is we'll want to return a new Cat and we'll pass the name, breed, and color. So since we are returning, it will never actually get to this portion of code, but the fact that it's not a Cat means that it wasn't actually new'd up correctly, that this would be the window, and so we'll actually want to say oh, well we accidentally came here through the window, let's actually kick off the process again, but this time let's new up the Cat. So even though I'm not saying new here, what will happen if we update this code, is it will still work, which is great. And so we've kind of protected ourselves against people who don't say new. Now again, it still works if we say new, either way it will work just fine, but that's a nice way to protect ourselves.
Inaccurate Increase Bug
In this inaccurate increase bug, we have a fruit array of strings and we're incrementing the index and the count to add two new items, orange and banana, and at the end we console.log the contents of the array. The desired output is listed above in the comment, apple-1, orange-2, and banana-3. Do you know what the output will be and can you spot the bug? (Pausing to spot bug) So unfortunately we didn't get the desired output, but you knew that we had a bug, so that was obvious. What we do get as output is orange-2 and banana-3, and that's it. So what happened to apple-1? Where did it go? So the reason things aren't working as expected is because we're using a combination of prefix and postfix operators, and we're also using them within a complex statement. This combination can lead to some confusing bugs. The difference between prefix and postfix is easy to understand conceptually, but in practice it could be easy to get wrong. Plus plus x returns the operand after adding 1, whereas x plus plus returns the operand as is and adds 1 after that. If these are on one line by themselves, it isn't too hard to understand, but once you start mixing them into a complex statement, all bets are off. For example, let's take a look at this code. We have a new array with y = 0. We concat the test string to ++y and assign it to our array. After that statement, the string is at index 0 and the value of y is 1. If we repeat this statement slightly, but used a postfix instead, then we get a result that we probably didn't intend, an array with test1 and test1. To fix our problem, we could split out the code to increment our variables onto their own line. Yes, it is more cumbersome, but the outcome is much more straight forward for developers to understand, and the chances of accidentally introducing an error is decreased. JSHint also helps us out here and lets us know that we're using confusing pluses, which should be a head up to us that maybe we should reconsider how we're coding this. Another solution to this particular issue is to use the length of the fruit array to both help insert a new record and also to help concatenate the string being stored. Since the length of the array will always be a value one higher than the last index, we can use it to append new records to our array, or we could also use the push method off the array to insert as well.
Summary
So that concludes our module on expressions and operators. As a review, you should be careful when you're doing floating point arithmetic, either consider converting to whole numbers or using a special library such as BigNumber to assist with precise calculations. You might want to consider using a utility method to determine the type of a variable, because typeof doesn't always give you want you need. Make sure you memorize the false values of JavaScript. There aren't that many and they'll come in very handy. Either learn the rules of the double equals comparison operator, or use the triple equals instead. Be careful with the comma operator, it's powerful, but it can be confusing. Remember to new up your constructors. You should also try to uppercase your constructor name so that other developers will know to new it up as well. And be careful when using the prefix or postfix increment operator, or better yet don't use them at all. A common exception is in the for head loop.
Function Bugs
Introduction
Hello, this is Elijah, and in this module we'll focus on Fixing Common JavaScript Bugs related to functions. You could reach me at my blog at elijahmanor.com, or feel free to Tweet me @elijahmanor.
Raised Resource Bug
In this raised resource bug, we have a global score of 1000 set outside of the play function. Once we call the play function, it will check to see if a score has been set, and if not it will log that it's setting a default value, and it will set score to 100. Do you know what the console.logs will say after the code at the bottom runs? Can you spot the bug? (Pausing to spot bug) The result for the console.logs is shown here in the box. Before we call the play function the score is 1000, which makes sense since that's what it was globally. Then once we invoke the play function, the next log says begin: undefined. Wait a second, what? Shouldn't it be 1000 at that point? The previous log said it was 1000, what happened? And since the previous log said it was undefined, it gets into the if statement to set the default value to 100. And then at the end of the function we log that the score is 100, which makes sense because we just set it to 100, so I'm good with that. But, once we exit the play function, it turns out the score is back to 1000. What in the world's going on here? Well as it turns out, there is an explanation to what was going on. There is a big difference in scoping between languages like C# and Java compared to JavaScript. Languages like C# use block scope. In other words, the lifespan of a variable is contained within a set of curly braces. For example, let's take a look at the following C# code snippet. This code won't even compile because we're trying to access the variable secret when it doesn't exist after the if statement. The secret variable's lifetime only exists within the if statement. By the time we exit the if statement, the variable is no longer accessible, and as a result we get a compile error. Well that's all fine and dandy, but once we move over to JavaScript, things are very much different. JavaScript doesn't have block scope at all, rather it has function scope, meaning that the lifespan of a variable is contained within a function and not within a scope of curly braces. For example, if we were to take the previous code and rewrite it in JavaScript, we would see a very different result. First of all there's no real compile process, so we don't get an error there, but if we call the test main method, we'd find that both console.logs output the string: all the things. What? How's that? Well, the variable secret inside the if statement isn't contained to that block, instead it's available to the whole function because JavaScript has functional scope. So even though we provided the var keyword inside of the if statement doesn't mean that the memory is contained in there. So what's really going on here? Sure, I get that scopes are different, but how does that explain the weird behavior that we saw before? Well, there's something called variable hoisting that turns out to be an important concept to know when writing JavaScript, and you'll find that one of the best practices you might hear is based on this concept. So when you end up declaring a variable, what really happens is that JavaScript will keep the assignment of the variable in place, but it will move or hoist the variable declaration to the top of the function. So in this code example, if we look where we had var secret inside of the if statement, the assignment of that variable is kept in place, but the variable declaration is moved up to the very top of the main function and it's initialized to a value of undefined. And this is the concept of variable hoisting. So if we come back over to our play function example, let's see if the output makes a little more sense now. Following the same rules that we talked about before, we'll keep the assignment of the score variable inside of the if statement, but we'll hoist the declaration to the top of the play function and set it to undefined. Now if we take a step back and look at our console.log, it starts to look more logical. So now we could see that we have a local variable score that has a lifespan of the whole play function and is initially set to undefined. So when the if statement looks at that local variable, it will want to set the default value. And then when we leave the play function, the score variable now refers to the global score and not the local one scoped to the play function. As it turns out, what we were trying to do in the first place was kind of silly. So to fix our code we'll just remove the var from inside the if statement and just let the code use the global variable at all times. Thankfully JSHint will warn us about our previous code that we already had a score variable defined. This is a clue that maybe we should be doing something different. However, if we really did want a local score variable in our function for some reason, then we should have declared it at the top of the function instead of way down in a nested block, that way it would be more obvious to another developer what was really going on. And this is actually considered a best practice among JavaScript developers, to always declare your variables at the top of your function, even if you don't need them yet.
Raised Resource Bug: Demo
So here we have the code for the raised resource bug, we're using jsFiddle and you can follow along at the URL above. Here on the right is our console log, and on the left is our code. This is a play function, we have a global score variable of 1000, and inside of our play function we're going to console.log the score, if it's not set we'll say that we're going to set it and then we go ahead and set a version of it, we console.log again what score is, and then at the very end after we call play, we'll actually log it again. If we look at our console initially it's 1000, which makes sense because that's our global variable, but then when we get inside the play function it's undefined, and that looks a little confusing based on this code right here. Then it says it's setting the default value, which I guess makes sense if it was undefined. We're setting to 100, it ends with 100, so that makes sense since we just set it. But then when we come out at the bottom, then we get 1000 again. Well if we didn't know about variable hoisting then this could be very confusing, but essentially what happens is this variable score is not contained within this scope. What really happens is the variable gets assigned there, but the variable gets hoisted to the top and it gets declared right here, so var score = undefined. And that's how JavaScript works; it hoists its variables to the top of function, because it doesn't actually have block-level scope variables like C# does or Java. So now it reads a little more sensical. If we come in here, now we could see that score is a local variable, and we're not talking about the global one anymore, and so when we say begin score, it's going to use the local version first, which is undefined. And so it does get in the if statement and sets the local version to 100, prints out that it's 100, but then when it leaves the function, where that memory was stored, now we revert back to the global score which is 1000. So it's very important to remember this technique. So as a best practice you'll want to declare all your variables at the top of your function, because that's what JavaScript's going to do anyway behind the scenes with variable hoisting. But this way, if you actually do it manually, it'll communicate to other developers what's really going on, because they actually might not understand what variable hoisting does, or your function might be so long and big that it's easy to miss if someone declared a variable way down in the deeps of some scope and you couldn't see it. Behind the scenes it would be hoisted without your knowledge and you couldn't visually see what's going on.
Early Execution Bug
Now that we've talked about variable hoisting, let's talk about function hoisting. Unfortunately the rule isn't exactly the same as what we just learned. However, it's an easy concept to grasp, so let's get to it. So let's take a look at the following example. Here we have two functions, a sayHello function and a sayGoodbye function. At first we try to invoke both the functions, then we declare them, and at the end we try to invoke them again. Do you know what messages will be consoled? Can you spot the bug? (Pausing to spot bug) Well here are the console messages. The first message makes sense, Undefined is not a function, because we haven't defined the function yet, we shouldn't be able to invoke it. However, look at the second message. What? It worked? How did that happen? At this point you might be questioning all of reality, but don't worry, I can explain. Before we do, let's look at the last two messages. Well, the last two look just fine. They console Hello and Goodbye as we would have expected. After all, our functions are defined from that point. So what's really going on? Well it turns out functions can hoist differently depending on how they were declared. Function expressions thankfully follow the variable hoisting rules we've already talked about, but function statements will hoist both the declaration and the assignment together to the top of the function. So the test1 function expression below follows the previous variable hoisting rule. The assignment of the function stays in place, but the declaration of the variable is hoisted to the function. Okay, so far so good. So the test2 function statement will follow the new rule that we just described above. Both the function declaration and assignment will get hoisted up to the top of the function. The difference is subtle, but it's important to know. So this is why we were seeing that strange behavior where we were able to successfully invoke sayGoodbye before it was even defined, but now we know that since it was a function statement, that the whole thing, declaration and assignment, were hoisted up, making it available for us to call. In order to fix our previous code, we just need to make sure our sayHello function expression is declared before we call it, so we moved it up to the top of our file. Or, we could have converted it to a function statement instead and let JavaScript hoist all of it when interpreted. However, JSLint will warn you if you're accessing a function before it's declared, even if it's a function statement.
Morphed Method Bug
In this morphed method bug, we have an overloaded text function that if called with no parameters will retrieve the innerText of our DOM element. If called with a string, then it will set the elements in our text, and if called with a function it will set the innerText of whatever is returned from the callback. Can you spot the bug? (Pausing to spot bug) Well, when we actually run our code what we find is that we get an exception, Uncaught TypeError: undefined is not a function. Do you know why? Well as it turns out, JavaScript doesn't support method overloading like some other languages do by default. However, you can fake overloading by doing it manually. If you've ever used a library like jQuery, then you know many of its methods appear to be overloaded. The way you do this is to provide one function, but make it smart enough to handle whatever input you want it to support. Since JavaScript is dynamic, you can pass any number of arguments you want of any type that you want. So in this overloaded function example, we're looking at an implicit parameter called arguments to determine how many items were passed to the function by looking at its length property. You could access all the individual arguments from this parameter as well, regardless if they've been named or not, and then you could check the type of your various arguments and respond accordingly. In order to fix our previous code example, we'll define one text function instead of three, and instead make our function smarter to change its behavior based on the arguments passed to it. So if the value passed is undefined, then we're going to take that to mean we want to get the value from the innerText. If the value isn't undefined and the type of value is a string, then we'll take that to mean we want to set the innerText to that value. And if the value is a function, we'll pass the current value of innerText to the callback and set innerText to whatever is returned from that function. And now we have a function that appears to be overloaded, but behind the scenes is a bit of argument-type checking trickery. Thankfully JSHint would have helped us out here because it would have said we've already defined the text method before. The reason why our code didn't work before is that each time we are redefining the text function again and again, so the last definition overwrote all the previous ones. Before we move on, since a big part of overloading functions is type checking, it might be good to talk about some of the gotchas of type checking. This is a little review from a previous clip, but checking types is such a big part of fake overloading, that it seemed appropriate to quickly rehash the topic. So there's a type of operator in JavaScript, and for the most part it's very helpful as we've seen, but there is a limit to its usefulness. Typeof does work fine on several different types, such as boolean, number, strings, functions, and undefined, but from there most everything else it returns object. For example, an array returns object, null returns object, etc. As an alternative approach, jQuery has a utility method. It has some extra logic inside of it to help decipher several other types, and will appropriately recognize an array, null, error, date, and even a regular expression. If you don't use jQuery, or if you already have Underscore, then they could be helpful as well. It has a suite of methods that can check types, such as isFunction, isUndefined, isNull, isArray, and others, that make checking types a little more thorough.
Morphed Method Bug: Demo
So here we have the morphed method bug. Here we are in jsFiddle, you're welcome to follow along at the URL above, but what we have is an exception here, so something's obviously wrong to begin with, undefined is not a function. If we look at our code, what we want to do is have this text function that's overloaded. So depending on how we call it, we want it to act a little bit differently. Here at the bottom, if we pass nothing we want it to be a getter, if we pass a string we want it to be a setter, and if we pass a function then we want it to be a setter, but only what the function returns do we want to set. So here's our element and we're dealing with innerText here. And so this is not going to work, and why it blows up is since overloading is not a native thing in JavaScript, what happens is every time I try to define a new text function, it just redefines the previous one. So here I define text, but then here I say oh, well now I want text to be this function, and when I got to the last one, well now I want text to be this function. And so these other two are kind of blown away and it's only the third one. So when I call text with no arguments, what happens is callback will be undefined since I didn't pass anything to it, and I'm trying to invoke undefined, which throws the error. So let's make this so it really works. What we're going to do here is we're going to say value. And then we're going to test to see if no one passed anything in as the value. If that's the case, then I want to return the innerText, I want it to be a getter. Otherwise, if the type of the value is a string, then I want to set the elements in our text to that value. Otherwise, if the type of the value is a function, then I want to actually set the elements in out text to the response of the function when I'm invoking it, so value will be a function in this case and I would actually want to send it the original innerText so that it has a chance to look at it, maybe tweak it out, but then it will return something and I want to use that to set the innerText. So now I could delete these other functions. So what should happen is when I call text with no parameters it should be a getter, and we're kind of throwing away that response, but whatever, and then we're saying now we want to set that particular element with the string Hello, so at the end Hello should be inside of this div. And then I'm going to call text passing a function, so this is another setter. What it's going to do is it's going to pass in Hello, because that's what it was before, and then I should append space World to that, return it, and that should get sent back to the element so the end result should be something that says Hello World! So if I run it, and sure enough, I get Hello World here. Let me clear the console so just to make sure an error did not occur. And sure enough, it did work here and there was no error, that error was from before. So this is how we could simulate method overloading, although it doesn't really support it out of the box, you have to do quite a bit of jumping through hoops, testing various arguments, and seeing what works, what doesn't work, etc.
Confounding Context Bug
In our confounding context bug, we have a student object with name and resume properties, and a study method. We're saving off the student's study method to a local memorize function, and then we proceed to call this student.study method, log his resume, and then we call the memorize function, and then log the student's resume again. Can you spot the bug? Do you know what will be logged in the console? (Pausing to spot bug) So as it turns out, if we ran this code we'd get something in the console first, John is studying chemistry, which is what we're expecting, but then we'd also get a runtime exception thrown, Uncaught TypeError: Cannot call method push of undefined. Can you spot the bug now? Well the bug comes down to the concept of the this implicit parameter. Remember how we talked about the special arguments parameter? Well this is also a special parameter and contains the context of the function. In the next slide we'll unpack this somewhat. If we have a top level function, hiWindow for example, and then invoke it, the value of the this implicit parameter will be the global object, which is the window object. If we have an object with a method, for example this person object with a greet method, once we call the greet method off the person object, the this implicit parameter will be the person, the object that invoked the method. However, if we saved off a method to a variable, for example, saved off person's greet method to a hello variable, if we invoke the hello function, the this implicit parameter is no longer the person object, but it defaults to the global object as our first example showed, and it will be the window object. At first glance that kind of stinks, but there are some ways we can manipulate the this implicit parameter to be what we want. We could, for example, use the call method off the function to change the value of the this implicit parameter. In this case we're making sure that the this context of the hiWindow function will contain the name of John, which is what we see here in the console log. Instead of using the call method off the function, we could have also used the apply method. They both let you invoke a function and control its this value, the main difference between the two is how you pass parameters. The next piece is going to show the bind method, which is yet another way to control the value of this. As in our last slide, we have a person object with a greet method. We could use the bind method off of greet to specify a context that will be used as the this parameter. Bind will return a new function that is ready be invoked and we'll keep the this implicit parameter to whatever you set it up to be, instead of being the global object like we saw in the last slide. So in this case we're binding person.greet to an object with the name of Jake. That way whenever we invoke the hello function, it will remember Jake as its this context instead of something else. And finally, we could have a constructor function, like we have a person here. The constructor function is meant to be new'd up, and inside the constructor the this implicit parameter is a new object that will be returned. So in this case we're creating a new person object, setting its name to Jane, retuning that object, and then calling the greet method, which will console.log its name property. So as a review, here's a chart showing what the this implicit parameter will be in various use cases. If you were to just type this in the console, or top level scope, you'd get the global object, which is the window in the browser. If you call a function that isn't off an object, then the this context will be the window. If you call a method off of an object, then the this context will be that object itself. If you invoke a function using the call method, then you can provide the this context as the first argument. If you want to pass parameters to the actual function, then you provide those as additional arguments to the call method as shown here. In the same way, you can do the same things with the apply method. The only difference here is that if you want to pass parameters to the function, you put them all in an array as the second argument to the apply method. ECMAScript 5 introduced the bind method, which allows you to wire up a context that will be used whenever a function will be invoked. Bind returns a new function that remembers the context you bound so that when it's invoked, the this context will be what you told it previously. And finally, if you have a constructor function, the this context inside the constructor will be the new object that was created and will be returned from the constructor once it's finished. So in order to fix our previous code, we'll use the call method off the memorize function and set the context to the student. That way, once it's invoked, the this implicit parameter will be the student and everything will just work as expected. We could've also just called the apply method instead. Or, when we assign student.study to memorize, we could have used the bind method at that point. Another change made is to store off the this context as the that variable, so we could use that inside of the addToResume function. This is yet another way you'll see some developers get around the issue of controlling context. There are lots of ways to solve this issue, the main point is just to understand what options are available and what's really going on. It turns out having our code in strict mode could have saved us in our previous broken code example. Strict mode eliminates the coercion of this to the global object. Without strict mode, invoking the hiWindow function or trying to call the greet method with undefined would coerce the this context to the global object, the window. But if we add strict mode, then both cases would not coerce to the window. The this context in the hiWindow function would be undefined, and the context in the greet is null since that's what we set it to. Without strict mode, undefined or null would get coerced to the window. Thankfully JSHint can help us out a little bit if we are in strict mode. Our previous buggy code example would have had the following JSHint error, Possible strict violation. In addition, our code would probably break since the object was not coerced.
Confounding Context Bug: Demo
So here we have the confounding context bug. We're using jsFiddle and you're welcome to follow along at the above URL. We have the dev tools open at the bottom, and we have our code here in the middle. What we have is a student object with name and resume properties and a study method. We're saving off the study method to a memorize function, and then what we're going to do is call student.study, saying that he's studying chemistry, then we'll print out the resume of that student, and then they'll memorize history, which is essentially just studying it, and then we'll print out his resume again. But what we find if we look in the console is things partially work, but not so much. We get a console log message that John Smith is studying chemistry, but then we get an exception, so let's take a look. Here we're calling student.study chemistry. We come into the study method, and obviously this console worked just fine, but then what happens, we have an inner function and then we were invoking that function. So we're passing in the subject, we're getting into the inner function. So what's happening is there is no resume, and so we're trying to call push, but there is no push, and so it blows up. So why is there no resume? It's because the this in here is specific to this add resume, it's actually the window object, and it's not the this of the study. So that's a problem. So one way people get around that is they will create a new variable, and a lot of times they'll call it that, and they'll save this off to it, and in here they will change this to that. And so now, essentially we've made it so that variable is the this from the study and not the this for this particular function. It's a little weird, but let's run the code. It'll work a little bit better. So now we have John Smith is studying chemistry, we could print out, sure enough, our internal resume has chemistry, but now we have a problem with our memorize function. We have result is studying history, well that's kind of weird because where did result come from? So let's look in here, memorize history. We'll come in here, the subject is history, and somehow this .name is result, which is really kind of weird. If we come down here to our dev tools, we could switch to the Result pane, which is this window, and we could actually look that window.name is result. It's actually looking at the name property off the window object. So when we call a function that's not off of an object, by default the this becomes the window, which is not what we want. So one way to handle this is to invoke the call method, which allows us to choose what the this implicit parameter to be when it's invoked. And what we're going to choose is we want it to be the student. So we want to invoke memorize, but inside of it we want the this to be the student, and then we're going to pass history as our parameter. So now everything works just as expected. John Smith is studying chemistry, his resume is chemistry, now John Smith is studying history, and now his resume has chemistry and history. Another way we could have changed this is to use the apply method instead. It also lets you choose what the this implicit parameter will be as the first argument, but if we want to pass arguments to the function, we actually have to put them in an array as our second argument. We'll run this and everything still works. Another way we could have solved this is used the bind method, which is an ECMAScript 5 method. Now what you do here is we call bind and then we tell it what we want to bind it to, so we want to bind it to the student. So that's what the this implicit parameter will be. It will return a new function that will remember what the this implicit parameter should be, because we bound it to the student. So now if we come back here we could revert this back to what we had before, and even though we're just calling memorize right here, instead of the this being the window, it will be the student because that's what we bound it to. So if I run this then everything again will work just fine. If we wanted to, we could actually get rid of the that this technique and instead use one of the other techniques that we just learned. So we could use call here. And what we'll do here is we'll say we want this, the this of the study, to be the this when it actually invokes the addToResume function. So it will come in here and this will actually be the this of the study and not the this of the function. So if we run this then everything still works just fine. So there are lots of ways you could actually manipulate what the this implicit parameter will be using call, apply, and bind, or using the that this technique. The main take-away is to know the various different techniques and how to use them to change the this implicit parameter.
Escaped Environment Bug
For the escaped environment bug, we have selected an unordered list element from the DOM, and we have a loop creating 10 list items, setting their innerHTML, adding a click event handler, and appending them to our list. Can you find a possible bug in this code? (Pausing to spot bug) This bug's a little tricky to spot unless you actually run the code. Here's a simplistic animation to simulate what's happening. If we come over here to Link 1 and click it, the click event handler will be invoked and it will console.log the index that was clicked. But wait a minute, it console logged that I clicked the tenth index. That's not right. It should have said index 1. If we move down to Link 4 and click, we'll see the same console log message. Hmm, that's not right. As it turns out, if we click on any of the other items, they all console log the same message, You've clicked 10. Do you know why? Well, although we're adding event handlers dynamically, the message that's displayed is created at a later point in time when the click event occurs. The value of the variable i will not be the same as it was when the event handler was wired up, it'll actually be whatever value i was after the loop was completed, which is 10. What we need is somehow to make the event handler remember the value of i at the point when we added it, which brings us to our next point. Closures, we need them. The Mozilla Developer Network defines a closure as a special kind of object that combines two things, a function and the environment in which that function was created. So in other words, a closure is a function in some special memory that you could access at a later point in time. Here's a simple example of a closure that MDN shows to explain this concept. We have a makeAdder function statement and its job is to make adding machines. Before we unpack how it works, let's first take a look at how we're going to use it. Down here we use the makeAdder and say, hey, make me an adding machine that knows how to add the number 5 to whatever I give it. So, makeAdder will create an adding machine that remembers the number 5, and will pass it back to you and will store it in the add5 variable. In the same way, we'll ask makeAdder to make another machine that knows about the number 10, and it will return a special new adding machine and will store it in the add10 variable. Once you have your adding machine, you can invoke them and pass a number you want to add to them. For example, if I pass 2 to the add5 machine, I'd get 7, or if I pass 2 to the add10 machine, I'd get 12. The reason that adding machines work is that they were able to create a closure around the initial value when it was created. So for example, when I call makeAdder with 5 as the argument, it gets mapped to the x variable, and then a function is returned, which will be our adding machine, and it accepts y as a parameter, which will be added to the initial x value of 5. But how does it still know the value x if the function was returned? Exactly, that function is enclosed around the variable x so when it needs it it can look it up in its special memory environment. Yeah, I know it's a little heady. It took me several times before I really grasped the concept. What I found is even if the theory doesn't make sense, the important part is to remember the behavior that we saw where it wasn't remembering the correct data. If you see that behavior, then try to remember, hmmm, maybe I need a closure, and then go look it up. So let's go ahead and apply this closure concept to our problem. The problematic code was the event handler part, so what we'll do is add a closure to the event handler to remember the index of the for loop so that when a log message is made, it can use the right value. Do to this, it looks a little weird, but we're going to have a function, and inside of it return a function that will log our message. Our adder function will accept an index parameter and will pass in the for loop's i variable as an argument. The inner function will be the actual event handler that is a closure around the index value, and when the user clicks on one of the list items, now it will show the appropriate closed over value, you've clicked on 1, you've clicked on 2, etc. As an interesting side note, JSHint will actually complain about this code saying that we shouldn't make functions inside of a loop. It actually would have told us this with a broken code as well, so let's refactor this just a little bit on the next slide. Not only are we going to refactor this just a little bit because of what JSHint says, but also it might make the concept a little bit cleaner and easier to understand, since the code won't look as weird. So what we'll do is we'll move out the function that returns the function into its own function statement below, and we'll call it clickHandler. Then we'll use the clickHandler in our loop, passing in the index. See, doesn't it look a little bit cleaner? The code works just the same, but we split out the function that creates the closure.
Escaped Environment Bug: Demo
So here we have the escaped environment bug, you can follow along at the jsFiddle URL above. We have an unordered list and here we're grabbing an instance of that element, and then we have a for loop going over 10 times. Each iteration in the loop we're creating a new list item, we're changing its innerHTML based on the indexed, and then we're adding some behavior. Here we're adding a click event handler. When you click on an item we want to actually say you've clicked on 1, or 2, or 3, or whatever the index was at that point in time. And then at the end we append the list item to our unordered list. And as you can see over here on the right, sure enough, it did create all these items and appended to the DOM, which is great. So if we come to click on one of these, we'll click on Link 2, and then Link 6, and 9. You'll see in the console it's actually giving us the same message every time, You've clicked 10, You've clicked 10, You've clicked 10, which obviously is not correct. This is the case because the console log, the code inside the callback, isn't invoked until later when I actually click the item. And at that point in time, i is set to 10 because i, once it got outside of the for loop, was set to 10. So every time I click on one, after that point in time, they'll always be 10. So what we really want is some way for this function to remember the i that was set at that point in time when it was bound, and not at the end after everything was done. So what we're going to do is create a closure, and the way we're going to do that is to have a function inside of a function. And we're going to return this one. So what we're going to do is we're going to have a parameter here, index, and we'll use that right here, and then we'll pass in an argument of i. And we're going to go ahead and put one extra level of parens around here, it's not necessary, but it helps communicate to other developers that hey, something special's going on here. So what happens is we pass in i, which is the index at that point in time, it will get passed in as the index, and then we're going to return a new function, this highlighted portion, that we actually want to be invoked when someone actually clicks on the item. So if we click on 2 for example, all 2 knows about is this function that's highlighted. And inside the function it's referring to index, but you notice that the highlighted code doesn't know anything about index whatsoever, so where does that come from? Well it comes from that closure. So a closure is a special function, the highlighted piece of code here, with some special memory, and that memory is what was created at the point in time when it was returned, and so it has some special memory that knows about index, even thought the highlighted code doesn't show index being passed in, it knows about that value, and so it can actually pull it from that special memory. So now if we come in and run our code, let's clear our console, and we start clicking, we'll actually get the appropriate indexes, which is great, because now the function that's being invoked remembers that number when it was created because it was enclosed over. So if we run JSHint we'll actually get an error that it doesn't like that we're making new functions inside of a loop. So what we're going to do is we're going to pull this piece out, right here, into its own function, we'll call it clickHandler. And so what we'll do here when we wire this up, it will look a lot, lot cleaner, is we'll say clickHandler, and we still have to pass in the index because that's what we want it to remember, but things look a little bit cleaner and all the confusing looking code is still in here, we still have a function that's returning a function because we want to create that closure, we want this function to remember the index so that it could actually pull from that special memory. But if I run this again and clear my console, we'll still get code that works appropriately and gives us the correct index. And still if this doesn't make total sense, the key point to remember is the behavior that we're seeing. So before we had code that couldn't remember a specific value, it kept giving us the same value over and over again. If you get into a situation like that in your code, it very well could be that a closure could help you, and so at that point in time you could just say, well let me look that up on the internet again and try to learn that concept. But it's the behavior you want to try to remember, and then hopefully use a closure from that point on.
Peculiar Parameter Bug
In our peculiar parameter bug, we have the function sum and average. The sum function takes n number of arguments and then will iterate over the numbers, adding them together, and returning the value. The average function uses the apply method to dynamically pass all its arguments to the sum function, and then divides by the number of arguments to return the average. Can you spot the bug after calling the sum and average function calls below? (Pausing to spot bug) Phew, did you find it? You may have thought there was an issue with the average method and how it was calling apply, but nope, the issue is with the forEach in the sum function. Let's assume for a minute that we're in a modern browser that has ECMAScript 5 support, there's still an issue. The problem is that the argument's implicit parameter is not really an array, so there's no forEach method off of it. Oops. Yup, arguments is not an array but it is an array-like object. Umm, what does that even mean? Well, arguments does have a length property describing how many items were passed to the function, and you can use the bracket notation to access each individual argument in the not so array. However, the buck stops there, there are no other array-like features beyond that. You can't call forEach or sort or join, or any of the other array methods. So one way we could fix this is just use a standard for loop and control our own index to iterate over the arguments. That's easy enough to do, and now our code's working just fine, we get 15 and 9.4. If we really did want to use forEach, then there's a nice little trick you could use to easily convert the arguments array-like object into a real array. What you do is invoke the call method off the empty array's slice method and pass arguments as the context. And now you'll have an official array to deal with and you could use the forEach method to your heart's content. And again, the code will work just fine, we get 15 and 9.4.
Condemned Criterion Bug
In this condemned criterion bug, we have an IIFE that's picking random numbers between 0 and 100 every 5 seconds. Can you spot the bug? (Pausing to spot bug) So, it turns out that arguments.caller and arguments.callee are no longer available when in strict mode, so you get an exception in the console, as seen here. Which brings us to a little bit of history, early versions of JavaScript didn't allow named function expressions, so if you had a situation like the following, there wasn't a good way to refer to the callback inside the map method here. So what you'd do is use arguments.callee. However, now you can name function expressions, so the preferred technique is to name your function like this, and we'll call it algorithm, and then inside of algorithm we could refer to ourself with algorithm instead of arguments.callee. So fixing our code isn't very hard at all. We'll just give our IIFE a name, let's call it randomize, and then we'll use that in our setTimeout, and bam, things work as expected. We start to get random numbers displayed in our console. And again, JSHint can help us out here. It would've caught that we should avoid arguments.callee. If we had not caught this at runtime, hopefully we would have caught it when we were Linting our code.
Summary
So in this module we covered various things you should try to keep in mind when using functions in JavaScript. You should try to declare all your variables at the top of your function, you should make a point to declare your functions before using them, and try to understand the difference between function statements and function expressions, and how they differ in hoisting. You should know how to simulate function overloading by checking how many arguments were passed and checking their types. You should be mindful of what the this implicit parameter is and how to change it based on your situation. You should know about closures and when you might need to use them. You should remember that the arguments implicit parameter is not a real array, but only has some array-like features. And you should avoid arguments.callee and arguments.caller, as they aren't available in strict mode.
Value, Variable, and Literal Bugs
Introduction
Hello, this is Elijah Manor, and this module's about Fixing Common JavaScript Bugs when using Values, Variables, and Literals.
Booked Byword Bug
For our booked byword bug, we have a collection object created here with an IIFE with some public methods, add, get, and delete. It also has a private array called items. Can you spot the bug in this code? (Pausing to spot bug) Well, we get an exception thrown of Uncaught SyntaxError: Unexpected token delete on this line right here. So then we're like umm, okay, I'll just update this method to remove and then map the delete to remove in my return object below, just like this. There, that looks better. And things start to actually work in modern browsers, but then when we go back and test our code in Internet Explorer 8, then bam, we get another exception of Expected identifier, string or number. Man, we just can't win. What's going on here? So it turns out that our root problem is that we're using a reserved word in JavaScript. These are words that are used in the language to mean something special, like if, else, function, new, a whole bunch of others, and delete. In addition, there are a whole set of reserved words that are set aside for possible use in the future, like class, export, let, import, etc. So we need to be careful not to use those either. One of the common ones that accidentally gets used and causes fits in IE8 is class. So the thing to know is that in ECMAScript 3, reserved were not allowed as identifier names, think property names, or identifiers, think function or variable names. The browser with the largest market share with ES 3 is Internet Explorer 8. But thankfully in ECMAScript 5, reserved words are allowed as identifier names, think property again, but they're still forbidden as identifiers, functions or variable names. So that's why things started to work in ES 5 when we renamed the delete function to remove, but then it as still broke in ES 3. And thankfully JSHint is here to rescue us again, it'll tell us that delete is a reserved word, and it will warn us. In order to fix the issue to work in ES 5 and ES 3, we could quote the delete key in our object, but that would make invoking it a little awkward since we'd have to use the bracket notation to invoke it. Another solution would just to be call it something else all together, like delete item or just remove like we did internally.
Booked Byword Bug: Demo
Here we have our booked byword bug in jsFiddle, you could follow along at the above URL. Here we have our code, we have a collection object, which is the result in an IIFE, we have add, get, and delete as our public methods, and we have a private items. What we're doing is we're actually exposing the items, even though it's private, just so that we can console.log and see what's going on. But before we even look at the code, we have an exception here, Unexpected token delete. So we come in here and we're like, oh well, obviously we don't like delete here so let's just name this remove because delete is actually a reserved word. And so we will call that remove, and then we will map delete to remove here, and now we will run it again. And now everything works just fine. Here we're adding some bacon and eggs and cheese to our collection, then we're logging the _items, which is our private information that we've exposed, then we get the 0th index, which should just be bacon, and then we delete the first one at index 1, which is eggs in the middle, and then we log it again and basically we've removed the eggs, so everything's great. But unfortunately, if we run this in IE8, we will blow up. So let's update this. Just to verify that let's update this, we'll copy this URL, we'll come over to BrowserStack, we'll paste in our URL, say show, and then we'll run it against IE8. We'll start our testing and it will kick up a VM and it will point to our URL that we want, which is jsFiddle, and then we should see an error, because IE8 runs ECMAScript 3, not ECMAScript 5. And sure enough down here there's an error, we'll open it up and show the details, and it's expecting identifier string or a number. And if we actually looked at the line number it would be inside of our return, so let's close this. So it's having a problem with this. There are a couple of ways we could have solved this. One is we could've put quotes around delete because delete is a reserved word. So in ECMAScript 3, reserved words can't be an identifier or identifier name, but in ECMAScript 5 keywords can be identifier names, which is why we're able to have a delete here. But if we want it to work in both, then we'll just put this in quotes, because that's okay, but then when we actually go invoke it we would have to use the bracket syntax and then pass in delete as a string here. Now this will work in both ES 3 and ES 5, so if we update this, copy this URL, go back to BrowserStack, type in our new version, kick it off. (Loading) So what we'll do is we'll open up our dev tools, and then we'll run it again. Let's open up our script, and we'll pull this up and then we'll refresh, and there we go, it works just fine. We have bacon, eggs, and cheese. It logs bacon and then it removed the cheese. Now we had to actually run this with the dev tools open because console doesn't exist with thte dev tools closed. So if we open them up in IE8, then the console logs will work just fine. But it does work, however, that's a little annoying that we have to do that. So to get around it completely we could just avoid using a reserved word at all and we could just call it remove here, or we could call it delete item, or pretty much whatever we wanted to do as long as we stay away from the word delete. And that will continue to work both in ECMAScript 5 browsers and ECMAScript 3 browsers.
Revealing Recall Bug
For this revealing recall bug, we have a Bank constructor function with a deposit and withdrawal method. We can new up our Bank and then proceed to add and remove money from our bank. Internally there's a fee applied to each transaction, and the balance is stored in an account balance property. Once we start interacting with the bank, can you spot the bug? (Pausing to spot bug) So this bug isn't that the code doesn't work, it's that we have accidently exposed information that we didn't mean to into the global scope. Two global variables have been created. Can you spot them? One of them is easier to spot than the other. The first one is with the amountWithFee variable in the withdrawal method. Since we didn't var the variable, JavaScript decided to declare it for us and make it available on the global namespace. The other accidental global variable is fee. Now this trick of assigning a value to multiple variables is valid in many cases, but if you try it as your defining variables, then it could come back to bite you. In this case, this.fee gets assigned to fee, but fee doesn't have a var in front of it, so JavaScript declares it and makes it global for you. Then, that value gets assigned to amountWithFee, which is declared locally within the deposit method. So you need to watch out for this one. So let's take a step back and look at various ways that things can become global. So if we have a name = John on our page, then JavaScript will notice that it hasn't been declared, and it will declare it for you in the global namespace. In this case that's not a big deal because we're already at the root level, we're not attached to an object or another function scope. The main thing to remember is if you don't declare your variables, JavaScript will for you on the global object, which is the window object. So in this case, even though it doesn't really help you much, it's a good practice to make sure you declare your variables with the var keyword. Here's another example, but this time with a greet function statement. Since we aren't declaring the greet variable, JavaScript will declare it for us, but it won't be local to the greet function, JavaScript will make it global off the window. So again, make sure you declare your variables with the var keyword. Now the greeting variable will be contained only within the greet function and will not be accessible off the window object. Another example is the mangle function statement. This one's a little tricky. We're using the var here to declare the index variable, but you'll notice there's no var on the length, so JavaScript will declare it for you and it will put it on the window object. So in this case we'd want to use the comma separator to declare multiple variables and actually assign them a value. And one final thing, these functions are global too, so you'll want to be careful about that as well. To help reduce the number of global variables, there are several simple techniques you could use, such as an object literal or an IIFE, and we'll take a look at those in the next slide. One way we could protect our code from the global namespace is to use an object literal. It's pretty easy to use and all you have to do is make an object using the curly braces and declare all of your properties and methods. The main thing to watch out here is the special syntax you need to follow. There are colons between keys and values, and commas separating the pairs. Once you have your object, that's the only thing on the global namespace, everything else is in your object. Another technique is called the IIFE, which stands for immediately-invoked function expression. In the past you may have also heard this technique referred to as the self-executing anonymous function, but it's more accurately known as an IIFE. Well enough about the name, what is it? Well first of all it does look pretty weird, and it looks like a lot of extra stuff, but trust me, it's all there for a reason. So let's unpack this for a bit. We're making an anonymous function up here, a function with no name. And then here at the end we're immediately invoking the function with parenthesis. Inside the function we're defining some variables and internal functions. The important thing to notice here is that we're returning something at the end of this anonymous function. Whatever we return at this point will be public property and methods, and it will be stored on the myObject variable. So in this example myObject will have access to the greet and mangle methods, but it will not have direct access to the name variable. The greet and mangle methods could access the variable of name, but not directly from the myObject. So those are the two main techniques to help save yourself from making so many global variables. There are actually several variations of the IIFE approach that you could use as well. In addition, you could declare modules to take care of some of this, either a node or in the browser, using something like require jazz, and soon in ECMAScript 6. So here we have surrounded our bank constructor in an IIFE just for some extra protection. We've also cleaned up the code a bit and made sure to declare all our variables when necessary. What you see here in this slide is very similar to what you might see in the JavaScript output that CoffeeScript generates when you use the class keyword. And as in many of our points, JSHint can help us out here and find some issues as well. Here's a listing of several errors that JSHint found as it scanned our buggy code at the beginning. You could see that it noticed that the fee and amountWithFee variables were never declared, and by doing so they were being exposed to the global window namespace.
Revealing Recall Bug: Demo
So here we have our revealing recall bug. In our jsFiddle you can follow along at the URL above. We have our bank constructor and we're passing in a balance, and we internally have a fee that we charge both on deposit and withdrawal, and then we're storing our balance inside of the account. We have two methods, deposit and withdrawal, and here below we are depositing $1000, withdrawing $250, we'll print out some information, and then we'll deposit back $250, and print out some more information. So let's take a look at our console and see what's happening. After we withdrawal $250, we're going to print out our bank, and sure enough you could see that we removed some money along with a fee, but then we're logging window.amountWithFee and window.fee. These are global variables that we should not be exposing, but accidentally now there's a value in amountWithFee, so we'll have to take a look at that in a minute. Then we're going to deposit $250, which works, if we look at our log now we have $995, but now we have 2 leaked variable on the global namespace, both amountWithFee we saw before, but now we actually are exposing fee which we did not mean to. So we'll come in here, we'll start with withdrawal since that's the code that we ran first, and it's pretty easy to see here that we weren't declaring amountWithFee. So when JavaScript sees amountWithFee it says oh, well that's not declared, I'll declare it for you and I'll put it off the window. But we don't want that, we want to actually tell JavaScript to keep amountWithFee local to our function. So if we run this again things will get a little bit better, now we're not exposing anything when we withdraw money, but when we deposit we're still exposing something on the window. So let's look up here, and this one's a little bit harder to spot. What we wanted to happen is we wanted to say this.fee, assign it to fee, a local version of fee, and assign that to a local version of amountWithFee because we have var here, but we were never declaring fee. And you can't put var there, so what really we could do to fix this is put a comma, so we have a comma separator as we're declaring variables. So before what was happening is fee, the this.fee, was being assigned to fee, which JavaScript was like oh, I don't know what that is, I'm going to declare it for you and put it off the window, which is not what we wanted. So by having the comma here, that tells us, well this is a continuation of declaring other things, and so I'll make sure it's local. So now we have a local variable amountWithFee, which is set to undefined because we didn't actually assign anything here, and then we're telling JavaScript we also want another local variable called fee, and we'll assign it to this.fee. So now if we run this code, now we're not leaking anything, which is great, and things are a lot cleaner. We could clean this up a little bit further by swapping these around, so let's move this over here, and then we will just put a comma here, and we'll indent this. So now we're both assigning initial values to both fee and amountWithFee so it cleans it up just a little bit. We could go even one step further and probably remove a lot of these variables if we wanted to, but for now we're going to show you yet another technique. We're going to use an IIFE, which it's not necessary in this case, but it's a good practice to be in because it will help possibly save yourself from leaking other things. And so let's move this inside of here, we'll indent that, and then at the very bottom we'll return the bank. You'll see this kind of format on the output of CoffeeScript if you use the classes in CoffeeScript. So this is not saving you too much, but it does save you if you want to put some private information up here that maybe you want to be shared across the constructor or the methods. This stuff will not be leaked on the global namespace, it'll stay within this function and not be exposed to the global namespace. So that's kind of a trick. In this case it's not getting us too much, but it's a nice pattern that you might want to follow.
Relative Realism Bug
In this relative realism bug, we have an HTML function that will either get or set the innerHTML of an element, depending on the values passed to it. If no value is passed in, then it will retrieve the HTML, if a string is passed, then it will set the HTML, and if a function is passed, then it will invoke the function, passing in the original HTML, and then set the HTML to whatever was returned from the callback. Can you spot the bug that's in this code? (Pausing to spot bug) Okay, so this is another weird one, but it's actually quite interesting. So everything works just as expected if this is all the code that was being executed, but someone could have redefined undefined to be something truthy, which could effectively mess up all your checks against undefined in your code. This could either happen maliciously, or accidentally, or as a prank. But wait a minute, what about all those reserved words we talked about earlier in this course, doesn't that help protect us from such silliness? Ah, but where's undefined? It's not listed. Well, unfortunately ECMAScript 3 didn't include undefined as a reserved word, and that turns out to be a bad thing since undefined is one of our seven falsey values that we talked about. Thankfully, ECMAScript 5 has identified undefined, and not a number, and infinity to all be read-only, so this won't be a problem if you're using a modern browser. In addition, JSHint will help us out some and tell us what we're doing is a bad assignment. So what we're going to do here to help us out is use an IIFE, we've seen this technique before several times, but this time we're going to use it for a slightly different reason. Before we start, let's talk about functions for just a minute. If we have a function like sayHello, for example, and only pass one argument to it, but accept two parameters, what will the value of the second parameter be? It's the value of undefined as seen here in the console.log, Hi John undefined. So we could use that concept to our advantage when using an IIFE. What we have here is an IIFE that we're only passing one argument to, but we're accepting two parameters, the one we're expecting and an extra parameter called undefined. As we saw earlier, what will happen is that JavaScript will make sure our undefined variable now has the undefined value. If the browser is ECMAScript 3, then this is a good thing, and if the browser uses ECMAScript 5, then it doesn't hurt anything. The final thing about this technique is that it could help with minification. Since undefined is now just a regular variable, a good minifier can replace instances of undefined with a short substitute such as o, for example, in this minified code. The end result could save a lot of bytes since every instance of undefined can be replaced with o, or something similar across your whole file. JQuery for example uses this technique. So one way to fix this problem is to wrap our code in an IIFE and have an undefined parameter that we don't pass any arguments to. That way it's guaranteed the value of undefined. You'll find this technique used in several places.
Relative Realism Bug: Demo
So here we have the relative realism bug in jsFiddle, you're welcome to follow along at the URL above. What we have here is some code with an HTML function. If you don't pass anything then it's a getter, if you pass a string it's a setter, and if you pass a function it will set the innerHTML to the response of that function. And everything actually works just fine. We have Hello World in the browser, we have some console logs, it's all returning just fine, but the main thing we want to show in this is that we can say undefined = true, and it could mess things up. Actually in ECMAScript 5 it doesn't mess things up because undefined is a read-only variable. However in ECMAScript 3, undefined is not read-only and it's also not one of the keywords, reserved keywords, and so it actually could cause problems in ECMAScript 3. So let's update this code, we'll copy the URL, and we'll come over to BrowserStack and run it in IE8. We'll wait for it to kick up a virtual machine, and what we'll do is we'll open up our dev tools because we're using the console, which isn't available without the dev tools, but if we open the dev tools the console is available. So let's refresh. We get Hello World here, but if we look at our script log then we get undefined and undefined. So if we look back at our code, what it wasn't able to do is figure out what the getter was. It was able to set them correctly because it was just testing against string and function, but it wasn't able to get the appropriate message from the getter and put that out to the console, because undefined was not able to get in here, and if we don't return anything from a function explicitly, undefined gets returned instead. So how do we fix this? Well one way we could fix this is to wrap it in an IIFE. So let's wrap this in an IIFE, and then we will copy this code. Actually for now we'll just put it all in there, and we will indent this, and then what we'll do is down here we won't pass anything in as an argument, but we will accept something as a parameter and we'll call it undefined. So the way JavaScript works is if you have a parameter with no matching argument, then its default value will be undefined. So in this case we have a variable called undefined, and its value will always be set to the value of undefined. So when we're actually testing against undefined, the variable here, we're actually guaranteed that the value will be undefined as well. So let's update this, get a newer URL, we'll come back over to our dashboard, and we'll type in our new version. And now it works in the browser and also the getters work as well, now we have Hello and Hello World. And another benefit of this is if this code was minified, then this is now just a standard variable. So a good minifier could replace this with like a u for example, and then any instance of that variable inside of this scope, it could replace with that same variable. And so you could just imagine this could really squish a file pretty small. JQuery, for example, uses this technique to help it minify as well.
Tangled Tag Bug
In this tangled tag bug, we have the following code. We're using jquery and jquery-ui. Let's assume we've pulled all the in correctly and we're good to go. We'll run the following script at the bottom of the page so the DOM will be ready at that point. We'll use jQuery to select all the date fields, and then we'll initialize those elements with the jQuery UI Datepicker. Can you spot the bug? Do you know what will happen? Hint, it works just fine in modern browsers, but there's an exception in Internet Explorer 8. (Pausing to spot bug) So again, you might not need to support IE8, but it's still a good thing to know in case you ever need to support it, or help someone else track down a bug in their code. The exception that we see in IE is, Object doesn't support this property or method, which is actually really confusing, so what's really going on here? Well there's something really interesting going on here. There's something called named access on the window object, which is described at this URL in more details, but basically what it says is that names of iframes, frame, and framesets will be exposed onto the window, certain elements with the name attribute will be exposed on the window, such as anchor, form, image, etc., and elements that have an id attribute will be exposed on the window. Wow, talk about cluttering the global namespace. So for this code snippet we have an HTML element with id of hello, and then a script that can set the elements in our HTML with a string. And this works because the browser made the div accessible off the window object. The above code is as if I had typed window.hello.innerHtml = Howdy, it still works and it shows that yes, indeed it is on the window. JSHint will help us out a little bit and tell us that datePicker is not defined, which isn't necessarily telling us about this exception, but it so happens that this is why we're having a problem, at least in some browsers. Let me explain further. So I mentioned that modern browsers don't have this issue and they just work, right? Well, they actually support this named access on window object too. So what's different? Well the difference is that Internet Explorer 8 not only makes them accessible off the window, but if you try to reassign them to something else you get an exception. So that's the difference. Other browsers expose these elements on the window too, but if you decided to reassign them to something else, no exception is thrown. So, this issue is partly with IE8 being weird, but it's a problem because we're creating global variables when it wasn't really necessary. Even if we did declare our datePicker variable, it would still be global in this instance. So what do we do? So to fix our issue we'll just create a simple little IIFE wrapper to keep our memory off the global namespace. That will keep our code from clashing with any named elements on the window. Another way you could have fixed this is just to use jQuery chaining and not introduce a new variable at all. In addition, you could have used the DOM-ready event handler to use as your function wrapper. We really just need something to place our memory in so it wasn't on the global namespace. However, for this simple example, waiting for DOM-ready isn't necessary since our previous slide had the code at the bottom of the page before the closing of the body tag, but I think you get my point. Just be careful of this so-called feature. I actually prefer not to rely on this named elements on the window, for some reason it just doesn't feel right.
Double Define Bug
For this double define bug, we have a person object with some name and address properties and a toString method. At the end we're console logging the results of the toString. Can you spot the bug? (Pausing to spot bug) So the error is, what we get in our output may or may not surprise you. You may have expected the phone number to be 555-123-4567, or you may have thought it would be the value below, which is what is really outputted. The issue is that we define the same key in our object literal twice, doh, and that isn't good and most likely it was a mistake. For silly examples like this it might be trivial to notice, but imagine if you have an object that's much larger, it could be really hard to miss in cases like that. So the main thing to remember is that the last key in object literal or a parameter in a function with the same name wins. So to see this behavior on a smaller scale, let's look at some snippets. Here we have an object literal with key1 listed twice. If we go to console.log myObject.key1, then we'll see the value that was last assigned. In this case key1 will be Goodbye.1. If we take a look at another simple example of a function with multiple parameters, if that happened to have the same name like param1, then whichever parameter was last would get the value. So if I called myFunction with Hello.2 and Goodbye.2, then the end result of logging param1 would be Goodbye.2. Thankfully JSHint will warn us about such things, that we have a duplicate key or a duplicate parameter. If we go one step further and turn on strict mode in ECMAScript 5, then these JSHint errors actually become runtime exceptions, so that's good. So we get an Uncaught SyntaxError: Duplicate data property in object literal not allowed in strict mode, and, down here we get Uncaught SyntaxError: Strict mode function may not have duplicate parameter names. So to fix our code what we'll do is put it in strict mode to give us runtime exceptions if there's a problem, and we'll also go ahead and remove the redundant object key to resolve that problem. And now there shouldn't be a question or confusion as to what the output should be.
Transform Total Bug
Yay! For the transform total bug, we have a purchase function statement that accepts an item and an amount. Inside the function it's parsing the amount, and then converting it to a fixed number in a console.log message. Then at the bottom we go to purchase some eggs for $1.00, and then we found some crazy expensive rare smoked bacon that costs $8.00. Can you spot the bug? (Pausing to spot bug) Well here's the output from our code. At first we got eggs for $1.00, which looks correct, but then we got our bacon for, what, free? That doesn't make any sense, it's supposed to be really expensive but hey, I'll take free too. But as it turns out that this bug is only in Internet Explorer 8, which by now shouldn't really surprise us. However in a modern browser we would've gotten the following results of eggs for $1.00 and bacon for $8.00. Well let's take a step back and look at parseInt, it takes two parameters. The first is a stringToParse, which is what we're passing. But the second parameter is a radix, which is optional, and we were not passing it. Here are the rules that are applied if the radix is not provided, undefined or 0, and the item to parse is a string. If it starts with a 0x, then the radix is 16, if it starts with a 0, then the radix is 8, and if it starts with something else, then the radix is 10. The exception to this rule is if you're using ECMAScript 5. In that case the radix will not default to octal, 8, if the string starts with a 0, which is why our previous example was working in modern browsers that use ECMAScript 5, but not in IE8, which uses ECMAScript 3. So the following examples, 0xA, defaults to base 16 and the value is 10, and 015 defaults to base 8 in ECMAScript 3 and the value is 13, or in ES 5 the base is 10 and the value is 15. Thankfully JSHint will let us know if we're missing the optional radix parameter. We don't want to leave this optional because ES 3 could pick octal when we didn't really mean it, so it's safer to always provide a radix, and most likely you'll say base 10. So in order to fix our buggy code, all we have to do is provide a radix of 10 and everything works as expected, although now we have to pay $8.00 for that really expensive bacon, maybe it was better free after all. Ha, not really.
Transform Total Bug: Demo
So here we have the transform total bug in jsFiddle, you're welcome to follow along at the URL above. We have a purchase function where we want to purchase an item, so eggs for example, and for an amount, so $1.00. We'll come in here and parse the amount, and then we'll console.log a fixed version of the amount. If we come down here, sure enough, we've got eggs for $1.00 and we got some really crazy expensive bacon for $8.00. Now everything's fine here, but if we come over and bring this URL to an old browser, such as IE8, then we'll have a problem. So let's go ahead and kick this up, we'll launch a VM in our browser, we'll have to open up our dev tools in order to see our console log. So let's come in here, we'll come over to the Scripts, and refresh. And what we'll notice is that eggs is $1.00, but our bacon that's supposed to be really expensive is free, it says $0.00, so that's a problem. So why it works in the new browser and not the old browser is that ECMAScript 5 has some different rules than ECMAScript 3. So in the old browser, ECMAScript 3, if a number started with a 0 and you did not provide a radix as the second argument to parseInt, then it would default to base 8, whereas we probably meant base 10. So it's really encouraged that you provide a radix so that the browser doesn't make it up for you. So we were going to say we want it to be 10 of decimal, and so that way it will in modern browsers or in old browsers. Now with ECMAScript 5, the reason it works is even if it starts with a 0, ECMAScript 5 says don't actually default it to base 8, they just removed that rule, so it'll assume 10, but for older browsers it assumes 8 if it starts with a 0. So what we'll do is we'll update this, grab the URL, come back over to our IE8, say show, we'll clean the console, and then we will run this. And sure enough we have $1.00 for eggs and $8.00 for our really expensive bacon.
Amount Aware Bug
So for this amount aware bug we have a similar problem as the last one, but a little bit different. Here our purchase function parses a float, and if the number parsed is not a number then we'll throw an exception, otherwise we'll console.log the item and the price with a fixed-decimal format. Then later we'll call purchase to get some eggs for $1.75, and then we'll buy some priceless bacon, the $8.00 bacon, wet our appetite for something even more exotic. So we found some bacon that's so rare and tasty that no price could describe its value. Can you spot the bug? Do you know what's going to happen? (Pausing to spot bug) You might be surprised by the result, or not. Here we have eggs at $1.75, but we kind of expected bacon to throw an exception, and it did not. Instead it printed out NaN as the price of the bacon, which is silly and it shouldn't be displayed. So what went wrong? Do you know? So this one has an easy fix. It turns out you can't compare not a number to itself using double equals or the triple equals operator. If you tried, you would always get false. So there's a special is not a number function that you need to call instead to test if the value is not a number or not. Thankfully JSHint will catch this and recommend that we use the is not a number function. So thankfully the fix is really easy, we just switch our quality from not a number to calling the is not a number function, and all will work as expected. We'll be able to get our eggs for $1.75 and the priceless bacon throws an exception because the number could not be parsed and was not a number.
Summary
So these have been some issues that you can encounter when using values, variables, and literals. Some of the issues we've discussed are trying to avoid using reserved words, being mindful that you aren't making global variables accidentally, trying to protect undefined from being redefined and also helping with minification, watching out for global DOM elements off the window and protecting yourself against the behavior, making sure you don't repeat object literal keys or function parameter names, trying to always provide a radix as the second parameter to parseInt so that octal isn't defaulted by accident, and trying to remember to use the is not a number function instead of trying to use the equality operator to test against not a number.
Object Bugs
Introduction
Hello, this is Elijah Manor, and in this module we're going to look at fixing some common JavaScript bugs when related to using objects.
Pregnable Property Bug
In this pregnable property bug, we have a web page where we're pulling in mootools and we have an array of customers. Then we have a for in loop that will console.log the key and the customer. Do you know what the output will be? Can you spot the bug? (Pausing to spot bug) So here's the output from our previous buggy code. Whoa, isn't that crazy? Where did all this stuff come from? That wasn't in our array, what's going on? Well it turns out the for loop iterates over all the enumerable properties of an object, including those that are inherited from its prototype, and since an array is just a special type of object, then the Array's prototype gets enumerated as well. One of the issues with the previous code is that we had MooTools on the page. MooTools in of itself isn't bad, but it does do something that we need to be careful about as we code. Both MooTools and Prototype.js add custom prototype methods to the Array, String, and other constructors, and by doing so, if you use for in on an array, it'll also pick up the message that added to that Array prototype. For example, in the following code we have an array with test1 and test2 inside of it, and then we're adding a wat property on the Array.prototype. When we for in over our Array, we console 0 test1, 3 test2, and wat WAT!?! So you can see how it's picking up the item we added to the prototype. You may also notice that it didn't iterate over index 1 or 2. The for in doesn't pick up those because they aren't part of the object. As an alternative to using for in on an array, we could have just used a standard for loop instead, that way you have full control over what index you want to examine. The output we get using this approach is much more expected. We don't accidentally loop over the prototype property and we also get to see all the indexes as is usually expected when looping over an array. So the for in loop is more suited towards iterating over an object than an array, however, you still need to be mindful of the prototype. In the following code snippet we're defining a Person constructor function and assigning a married property onto the Person.prototype, then we're newing up a new John Person, setting his marital status to true, and then doing a for in loop over his properties. As you can see, not only did it pick up his name, but also the married property on its prototype. This may or may not be what you want, it could be that you only wanted the immediate properties and not those on the prototype. If that's the case, then you can call a special method off the object called hasOwnProperty. By calling this method, we could check if this object directly owns the property, or if it's something that's inherited from a prototype. In this case, we only console.log a message if the object owns the property, and now our console will only output the name and not console.log the married prototype property. So there are two ways we could have solved this problem. One is to keep using the for in loop on the array, but to call the hasOwnProperty before logging a message. By doing so you get the following output. Or, you could instead use a standard for loop, controlling your own index, that way you could iterate over every index, which is usually what you want when you're looping over an array. Here is the output using that technique. Note, you could also use the for each method is ECMAScript 5 to iterate over the array as well, or use various each utility methods off of jQuery or Underscore. In addition, JSHint helps us out here a little bit and will remind us to use the hasOwnProperty method if we're using the for in loop as seen in this screenshot.
Pregnable Property Bug: Demo
So here we have the pregnable property bug in JSFiddle. You're welcome to follow along in the URL above, but we're pulling in MooTools the library, and here we have an array of customers with John Smith, Susan Smith, and Jane Smith. We're using a for in loop and we're console logging the key and the particular customer that we're iterating over. So if we look in our console we have 0 John Smith, 1 Susan Smith, and 10 Jane Smith. First of all, it's kind of missing some of the indexes that we might need or may not need, and also it has tons and tons and tons and tons of other stuff in the console. That stuff is being picked up by MooTools because MooTools is adding a whole bunch of methods and properties onto the array prototype, and the for in loop will actually iterate not only over the items on the customers, but also on the prototype. So we probably don't want to iterate over those things, and what we could do, thankfully, is we could call customers.hasOwnProperty, which is a special method, and we'll pass in the key that we're using, and we'll basically ask it hey, this key that we're iterating over, do you actually own it on this particular object or is it being inherited from the prototype? And in this case we only want the ones that own the property on the object, we're going to ignore the ones that are bleeding in through the prototype. So if I run this again, now we'll only get the items for this particular object and not the ones in the prototype, so it's nice. Another way you could do this is just have a standard for loop, so we're going to have i and len, and then we're going to have a standard for statement, i = 0, and then we're going to say len = customers.length and i is less than len and then i++, and then inside of here we'll just console.log i, and then we'll have customers sub i. We'll run this code and here we're actually picking up all the indexes that are undefined, so you may or may not want those. Another way we could have done this is we could have used for each, which is an ECMAScript 5 function, and then inside of it we would accept the customer parameter, and we could just console.log the customer. And actually there's an index it'll pass us if we want to pick that up as well. Now the thing with for each, for each will actually not iterate over items that are undefined, and so you'll see when we run this, we only get John Smith, Susan Smith, and Jane Smith, kind of like the for in loop above, the output is similar, but they're behaving very different. So, just keep those in mind for various ways to loop over things, especially the hasOwnProperty is a very interesting method, and usually the for in loop is intended for objects you'll find, and if you have arrays you'll probably want to either use one of the following two techniques.
Accidental Ancestry Bug
For the accidental ancestry bug we have an Animal constructor function with a name property and eat and sleep prototype methods, and then we have a Cat constructor that inherits from the Animal.prototype. The Cat overrides the eat method wherein the Cat immediately falls asleep after eating. Can you spot the bug? (Pausing to spot bug) Well the problems with our code aren't obvious until we start creating other animals, like Dog for example. Let's create a Dog that inherits from Animal, and then will override its sleep method, and let's say these dogs are mean so they're going to attack humans before they sleep. And now we're going to switch gears and create a sweet, calm little Cat named Fluffy, and have it eat some food. And here's the output. Fluffy starts to eat like we expected, and then bam, our sweet little kitten is now attacking me, ah, take cover! So, what exactly is going on here? Well, since we assigned Animal.prototype to the Dog.prototype, we essentially are now sharing the same reference. So when we modified the sleep method, we weren't overriding it, we were re-riding it. Our next problem can be viewed down here. If we use the instanceof operator on our Cat instance, it'll return true to being an instance of an Animal and a Cat, which is great. However, if we compare what constructor was used to create it, it thinks it was created with the Animal constructor. It would be nice if it would tell us that it was created with a Cat constructor instead. So let's see what it would take to fix these two issues. It turns out that fixing these issues is pretty easy to do. In order to break the connection between the subtype and the supertype, all you have to do is create a new instance of the super prototype and assign it to the SubType's prototype. That way if you change the SubType you aren't also changing the SuperType, which is what was happening in our previous slide. The next thing we need to fix is the constructor. That's also an easy thing to fix, we just set the SubType's prototype constructor to the SubType constructor function. And now when we create a new subtype, the instanceof will be correct as we saw before, but now the SubType constructor will be equal to the subType.constructor function. Yea! So in order to fix our problem, we just need to make two minor changes, we need to Object.create our Animal.prototype when assigning it to Cat's prototype, and we need to set the Cat.prototype constructor to the Cat constructor function. And that's it. As a side note, you may have noticed some redundant code in the previous example. Well, if we have a subtype, then in the constructor we can call the SuperTypes constructor by saying Animal.prototype.constructor.call this, name. Yeah, that's a lot to type, but it's better than repeating the functionality again. In addition, if you're overriding a method and want to call the supers version of that method, for example in the eat method, then you could call Animal.prototype.eat.apply this. Again, that's nice so you don't have to repeat the code in your subclass.
Accidental Ancestry Bug: Demo
So what we have here is the accidental ancestry bug in JSFiddle, you're welcome to follow along at the URL above. So what we have here is an Animal constructor function with a name, and we have two methods, eat and sleep. And then we have a Cat constructor function and we're inheriting from Animal, and we're going to override the eat method and say that the cat is eating, and then the cat immediately goes to sleep, because that's what cats do. And then we'll have a Dog constructor function, it'll inherit from the Animal, and we're going to override its sleep method and the dog is going to attack a human before it goes to sleep, because that's what dogs do. And then we'll create a new instance of Cat, let it eat, create a new instance of Dog, and let it sleep. And then we have some additional console.logs, but we'll take a look at those in a minute. So let's come down to our dev tools, we'll look at our cat, our cat starts eating, but then wait a second, it starts attacking humans, what's it doing, that's kind of weird, but then it goes to sleep. And the dog behaves like we want it to, it attacks humans and then it goes to sleep. So we need to fix that code somehow, but before we do let's look at these last logs and see what it's talking about. So there's an instanceof operator, and the cool thing is we can say cat, are you an instanceof an Animal, and the answer is yes. And we can say cat, are you an instanceof a Cat, the answer is yes. But if we want to actually figure out who created this particular object, if we look at the constructor, cat.constructor are you the Animal, that's true. We would rather have cat.constructor equal to Cat be true. So we would like to flip these last two so we could actually figure out which constructor actually created this object. So those are the two things we're going to try to fix, one to make a cat not attack people, and two, to make the constructor logic correct. So the reason the cat is attacking someone is because when we looked at the dog down here, when we actually told it what to inherit from, we said Animal.prototype, we're going to assign you to the Dog's prototype. So essentially at that moment the reference for Dog.prototype is now the Animal.prototype. So when we go to change the behavior of sleep, we're actually changing the behavior of the animal's sleep. And so Cat is inheriting from Animal, so now the Cat is picking up whatever we changed down here, so now he's going to attack. So the way to get around this is when you actually set the prototypes you want to say Object.create, so you're creating an instance of the Animal.prototype and assigning that instance back to the Cat's prototype. We'll do the same thing for the Dog, and essentially this is breaking that tight bind between the two. So now if we come back over here and run our code again, the cat will no longer be attacking us because now it's separate, which is good. So in order to fix the constructor, what we're going to do is we're actually going to tell it which constructor it used, and so in this case we're going to say it used a Cat. And then we'll use the same technique for the Dog, change Dog here, and we used a Dog constructor function there. And so now we'll run this code and now these last two have flipped, which is good, so now the Cat constructor is using the Cat constructor function, true. One other thing that we're going to do before we stop is you might have noticed a lot of repetitive code. So for example our Cat constructor is running the same code as our Animal constructor does, but if it's inheriting it, why is it repeating the code? So let's get rid of that and what we're going to do is we're going to say Animal.prototype.construtor.apply this, and we're going to pass the arguments that the Cat constructor got. We're going to use the same technique for the Dog because the Dog was repeating the same code too. So now if the code in our Animal constructor changes, we don't have to actually change code in the Cat or the Dog. So I'll run this code and make sure everything still works. That's good. So the other thing we repeated is when we overrode the eat method, we actually repeated the code that was in the inherited method. So wouldn't it be nice if we didn't do that? So we're going to say Animal.prototype.sleep, and then we're going to apply and pass this. And we will do the same technique for when we over override sleep. So let's remove this, we'll come over here and we'll, so now we'll run our code again and everything works just as expected, but now we have reduced duplication, we have made it so the objects are separated, and we've also made it so the constructors are fixed.
Eccentric Envelope Bug
For the eccentric envelope bug we have an array of contest strings and an isWinner function. The isWinner function will use the ECMAScript 5 some method to see if there are any items in the contestants array that match the name and happen to be a winner. If there is a winner, then a console message will be displayed with a happy face, otherwise a frowny face will be displayed. And here at the bottom we're calling the isWinner function twice, once with Elijah Manor as the name and the winner with false, and another with a string of John Smith and the winner of true. Do you know what will be console logged? Can you spot the bug? (Pausing to spot bug) So it turns out that neither Elijah Manor or John Smith are winners, although we were sort of expecting John Smith to be a winner. I mean his name is in the contestants array, right, and we mention that he is a winner, so what went wrong? So JavaScript has five primitive types, boolean, number, string, null, and undefined. It also has three constructor wrappers, Boolean, Number, and String. If we typeof a native boolean, we get boolean as a result. If we typeof a Boolean wrapper, we get object as a result, which makes sense, but it's kind of a bummer. If we triple equals compare a Boolean true wrapper with another Boolean true wrapper, then those are not equal because it's comparing object references, which are not the same. If we double equals compare a primitive true boolean with a Boolean true wrapper, it will end up being true because the double equals will toPrimitive the wrapper, which will call the valueof method returning the primitive value. In the same way if we typeof a native string we get string as a result, and if we typeof a String wrapper we get object as a result. If we triple equals a String wrapper with another String wrapper containing the same content, it'll be false because they're different object references. However, if we double equals compare a string primitive with a String wrapper, both containing the same content, it will return true because the object will get passed through toPrimitive, which will return the valueof, which is the primitive string contents. So in order to exterminate this bug, the easiest thing to do is just to not use the Boolean wrappers. Actually, in most cases I would recommend not using them at all. There are some use cases for them, and we'll talk about those in a minute. After removing the wrappers and using primitive strings and primitive booleans, we now get the output that looks like what we expected. Elijah is not a winner, but John is a winner. Thankfully JSHint will help us out and tell us not to use the String or Boolean constructor wrappers. Yea, JSHint! So when do I suggest using the wrapper or constructors? The safest place I've seen to use them is when converting between types, and even then there are alternative ways to do it. To convert a type to Boolean, there are two ways to do it. One is to double not the expression, this does look a little funny at first, but by notting the expression the first time, it will convert its value to a Boolean and flip the bit to the opposite. So if we want to find the original value, we have to not it again. It's weird, but it's something that you'll commonly see in JavaScript code. Another way to convert to a Boolean is to use the Boolean constructor without using the new keyword. It will return a converted Boolean representation of whatever you pass as an argument. There are several ways to convert a number to a string. You could use the String wrapper constructor without using new and just pass in the number you want to convert, or you could use the plus operator and concatenate an empty string, or you could use something really strange and use two periods and call the toString method. Why two periods you ask? Well if we only had one period JavaScript would think it was a decimal, but if we gave it two periods, then it will convert it to a Number wrapper behind the scenes, and then you could call the toString method. There are also several ways to convert a string to a number. You could prepend the plus operator to the string and it will convert it to a number, you could use the Number wrapper constructor without using the new keyword or you could use parseInt, making sure to pass the second radix argument. One reason you might want to use parseInt rather than the first two techniques is that it's a little more forgiving. For example if I had a string that contained 42 is the answer, then not a number will get returned from the first 2, but parseInt would at least capture the 42 portion and return that.
Eccentric Envelope Bug: Demo
In this eccentric envelope bug we have a contestants array and we have an isWinner function. At the bottom we're going to call isWinner twice, one passing in Elijah Manor as the name and the winner as false, and the other one we're going to pass in name of John Smith and winner as true. So what the function is supposed to do, it's supposed to look to see if the name that we pass is actually in the contestants array to make sure they're not cheating, and then we'll double check if they said they won or not. So if their name is actually in the contestants array and they said they won, then they get a smiley face, but if their name is not in the contestants array, or they said they're not a winner, then they get a frowny face. So if we run our code we actually see two frowny faces, Elijah Manor frowny, John Smith frowny. But we kind of expected John Smith to actually win, because John Smith's name is in here and he said he was a winner, so why didn't he get a smiley face? Well the main problem with this piece of code is we're using the object wrappers, String and Boolean, and that unfortunately confuses things quite a bit, especially when we start using the triple equals operator and not the double equals. We've already talked about how the double equals is kind of confusing, in many cases it does a lot of type coercions and you could follow the rules if you know the rules, but if you don't it could get very confusing. So what's happening here on the one that should of worked is we're passing in a John Smith String wrapper and a Boolean String wrapper with true in it, we come into the isWinner function, passing in our person, we're going to call contestants.some, and it's going to loop over and figure out if any of these are true. The name is our String wrapper and we're going to compare it to the contestant, which is one of the strings in our array. So a contestant will be a native string, and we're going to triple compare it to person.name, which is a String wrapper. If we use the triple equals, if the types are different, then it's going to be false, and in this case one's an object, one's a string, so it's always going to be false. And so that's why it's not going to work. So one way to fix this is to just get rid of the String wrappers. And for the most part it's usually a best case not to use the Boolean wrappers as well because you could get into some strange issues there, so let's just take out all these and we'll run again, and now we get Elijah Manor frowny, but John Smith smiley, yea, he won. So the main thing to think about here is just try to avoid these wrappers. So we're going to switch to JS Console here for just a minute and talk about when you might want to use the constructor functions for Boolean, String, and Number, and you might want to use Boolean if you want to convert things to a Boolean. So for example we talked about things that are falsey, so obviously false is falsey, but let's talk about empty string we actually about as falsely, so we'll actually get a false there, 0 is falsey. Things that are truthy are anything that aren't those 7 that we talked, so the number 5 for example, that would be truthy, and we could see those there. Another way to make sure if things are falsey or not, if you don't want to use the Boolean wrapper, is the not not. So if i not notted 5, that's true. The reason that works, we've talked about this before, but if I had 5 and I not it, then that converts it to a Boolean, but then flips the bit to false, but we really wanted the original value so we have to flip it again and get the original one. If we wanted to convert a number to a string we could use the String constructor wrapper and we could pass something into it like a 42, and you notice we get a 42 there. Another way is we could have concatenated a string that gives us a string as well. The reason that works is the plus operator, if either side is a string it will convert the other side to a string, so that's why that works. And here's a really weird one. If we say 42..toString, that will actually give us the string 42. Now why period period? Well if it sees the first period it thinks that's the decimal, but as soon as it sees another period, then it's like oh, that's something special, it'll actually convert that into a number using the Number constructor, and it has a toString method on it and it was able to convert it to 42. Now if we have a string and want to move it to a number, we could just put up the plus operator before a number, and that will convert it to an actual primitive number, so 42 right there, or we could use the Number constructor function wrapper and pass in the string 42, that converts it to a number. And then we know about parseInt whereas we could pass in a string, and we want to make sure we pass the radix as we talked about in a previous one, and then I'll parse to it 42. Now you might wonder, well which one should I use, parseInt, number or the plus operator, or there's a parseFloat for example. Well parseInt is a little more flexible where if I had something called 42 is the answer, and I passed in 10 as my radix, then it'll actually be smart enough and pick up all the numbers until it reaches something that it doesn't recognize as a number. So it'll still pick up 42, where if I tried one of these other techniques, 42 is the answer, then it'll just kind of give up and say not a number. So those are some use cases when you might want to use the wrappers, constructor wrappers, but of course there's other alternative so you're not limited to those, you could use the other ones instead.
Translate Time Bug
In the following translate time bug, we have some sample data that we're pretending is coming back from the server, and then we're using the ECMAScript 5 map method to iterate over the items and slightly transform what each record will look like. Instead of having uppercase Name we'll lowercase the name, and instead of having uppercase Birthday, we'll lowercase the birthday, and we'll also new up an instance of the date object based on what was passed from the server. Can you spot the bug? Do you know what will happen? (Pausing to spot bug) Well it turns out there isn't an error at all, but the result we get is not what we want. What we end up getting is an array that looks something like this. We were able to transform the keys to lowercase, which is good, name and birthday, but if you notice, the values of the birthdays, they say Invalid Date. Hmm, that's not so good. So what's the problem? Well in this case the date came from an older version of .NET, and it serialized the date to some strange Unix Epoch value with some strange extra information stuck in there. If we try to pass that to the Date constructor, it can't figure out what we meant, so it ends up being Invalid Date. Thankfully there's a nice utility date library called Moment.js, which allows us to convert this format for us. We'll see in our next slide how it can help us out even more. Thankfully with Moment.js it was really easy to fix this issue, we just pass the serialized date string into the Moment.js function, and then call the toDate method, and voila, the output looks much better. We have updated keys and a correctly parsed date. Yea, Moment.js! In addition to parsing older serialized .NET dates, there are many other handy features that Moment.js can do. I can format dates, and you could choose from a lot of different formats or create your own. It has a timeago feature, which basically means relative time, so you could see if a date is 2 years ago or 32 minutes ago, or in 28 minutes. Many social programs display their dates like this. And there are a bunch of calendar time methods like adding and subtracting amounts of time to or from an existing date. There's so much more you could do with the library. If you need to do stuff with dates, this is my go-to library. It's small and jam-packed with date goodness.
Perpetual Property Bug
For this perpetual property bug, we're going to create a read-only property called MEANING_OF_LIFE, and assign it the value of 42. Below we're going to console.log property, then assign it to a different value of 24, and then console.log it again. Do you know what's going to happen? Can you spot the bug? (Pausing to spot bug) Well, the output for this is 42 and then 42, even though we tried to assign it to a value of 24. What? Well actually, this might not be a huge surprise to you, but it might be surprising that it didn't complain at all. So ECMAScript 5 doesn't throw an error if you try to redefine an immutable or read-only property. For example, we could redefine undefined here and it will just ignore it, however, if we're in strict mode, then trying to change a read-only property will throw an exception from JavaScript as seen here, Uncaught TypeError: Cannot assign to read only property undefined. So in this particular case we aren't going to fix the problem, we're just going to put it in strict mode so that it will alert us that there is a problem. And here you'll see the error in our console. And then at that point we can update our code accordingly based on whatever we're trying to do. At this point it's mainly trying to get us information as quickly as possible, that what we're trying to do isn't working as expected. If we didn't have a warning like this, then it could've taken us a long time to figure out what we were doing wasn't really working.
Strange Set Bug
For this strange set bug we have two new arrays, one for an easyCombination with one number, and one for a hardCombination with three numbers. Then we decided we want to combine the easy and the hard arrays to generate a combined combination array. Finally, we console.log the array. Do you know what the resulting combined array will look like? Can you spot the bug? (Pausing to spot bug) This is actually kind of a weird one. Here's the output of the combined array. What? Does that even make sense at all? I was expecting an array of four items in it. What's even going on here? Well as it turns out, the Array constructor is overloaded, so depending on what parameters you pass it, it'll behave differently. If you new up a new array with no parameters, then it just creates a new empty Array. If you provide several arguments to the Array constructor, it'll new up an Array initialized with all those elements. So in these examples there are three items in each array, however, there's another overload where if there's only one argument and it happens to be a number, then that means something very special. It means that you want an array with that many entries that are all set to undefined, which seems a little strange to me. In order to fix this, we'll just use array literals instead of the Array constructor. And as you can see, the output is much more reasonable. It's a new array with four items from both arrays above. There is varied help with JSHint and JSLint about this particular issue. If you're using new Array to make an empty array, both linters will encourage you to use the array literal syntax, the square brackets. If you're using the special numeric 1 argument overload of the array, then neither of them will complain. They understand this means something special, so they'll let you do it. And in a similar fashion, the linters will encourage you to use the literal syntax if you're using the new Array to pass multiple arguments.
Malformed Message Bug
In this malformed message bug we have a string of JSON from the server, and then we go to parse it using JSON's parse method, and then we'll console.log what we parsed. Do you know what will happen? Can you spot the bug? (Pausing to spot bug) Well, all we get in our console is a big red exception, Uncaught SyntaxError: Unexpected token n. Umm, what does that even mean? It seems kind of cryptic, doesn't it? Well, as it turns out, the format of our JSON was incorrect. JSON, which is a string, is different from an object literal, which is an object. JSON is actually a subset of the object literal notation. So what does that mean? Well, JSON keys need to be double quoted and JSON strings need to be double quoted. Here's an example of both. You'll notice that the keys in obj1 are not quoted, whereas the keys in json string are double quoted. Also, the string in obj1 are single quotes, whereas the keys in the json string are double quotes. Object literals are much more flexible, I could have single quoted or double quoted all of its keys, or decided to double quote the strings if I wanted to. Quotes around keys in an object literal are optional unless there's a special character in them that's not valid in an identifier, or a variable name, which brings me to another point. There is no such thing as a JSON object. JSON is a string, it's not an object. It represents serialized data that typically comes from the server, but you could also store it in other places. So in order to fix our problem, we'll fix our JSON and use double quotes where they're necessary. As a side note, hopefully you aren't manually creating all of your JSON by hand, or rote code to generate your JSON with string concatenation or a template. There are great open source JSON serializers in most languages and libraries, and many that are native with server technologies. It's considered best to use these and not try to output or tweak your own. By doing so, hopefully you won't run into this problem. Anyway, once we fix our issue then the code works just like we expected. Here's the parsed object in our console.
Malformed Message Bug: Demo
Here's the code for our malformed message bug, we're in JSFiddle and you're welcome to follow along in the URL above. What we have here is the dataFromServer string, which represents our JSON that we're simulating coming back from the server, and then we're trying to parse it using JSON.parse, and then we're going to log in to our console using JSON.stringify. If we run the code we'll immediately get an error saying SyntaxError: Unexpected token n, which is not very descriptive. But if we look at our JSON, it's not actually valid JSON. JSON has quotes around all of its key names, and if there are strings it has to use double quotes, it can't use single quotes. So for example, let's come back in here and change some things around. Since I know I'm going to have double quotes inside, I'm going to use single quotes outside. So we have to double quote our keys, and then I'm going to double quote our strings. So here's the key I have to double quote, and then here I have to double quote my string, and double quote this other string. Now age is a key so I have to double quote it. Now number is 28, I do not have to quote it. So if I run my code again, sure enough it parses it, I do not get an error, and then when I stringify it and format it a little bit, then it will print out accordingly. Now with object literals they're a little bit different. Let's take this and make an object literal. I can essentially take the contents of what was in my JSON and it could be a valid object literal. Now there are subtle differences where I don't have to have quotes around my keys if I don't want to, as long as they're a valid identifier. So I could decide to take off these quotes if I wanted to, or I could have single quotes if I wanted to, they're pretty flexile as the keys. Now if I had a special character like a dash, like na-me, then I would have to put quotes around it, or single quotes. But as long as it doesn't have anything special around it you could just take the quotes off. Now our strings for an object literal, we could use either double quotes or single quotes, it doesn't matter, however, JSON is much more strict, and so you kind of have to follow those guidelines. So it's important to know the distinction between the two, and hopefully you're not manually coding this, hopefully your JSON comes from the server with some kind of a special library.
Summary
So we finished reviewing some common bugs that you might encounter in JavaScript when dealing with objects. We covered that you should try to use for in loops on objects, and use the hasOwnProperty method, and when you have an array, to just use the standard for loop. We talked about using Object.create when creating a subtype, and also setting the constructor correctly. We talked about avoiding the wrapper constructors unless you're going to use it for a conversion. We talked about being careful when converting dates, and that the Moment.js library is a handy utility if you need it. We talked about how strict mode can help you avoid accidental assigning to read-only variables. We talked about using the array literal syntax instead of using the Array constructor, unless you really did need to create a handful of entries initialized to undefined. And finally, we talked about the difference between an object literal and JSON, and encouraged you to use a library to do your serialization.
Course author
Elijah Manor
Elijah Manor is a Christian and a family man. He is a Microsoft Regional Director, Microsoft ASP.NET MVP, ASPInsider, and IE userAgent and specializes in front-end web development. He enjoys...
Course info
LevelIntermediate
Rating
(197)
My rating
Duration3h 42m
Released21 Aug 2013
Share course