Forgiving “Silent” Errors in JavaScript
There is a class of “silent” errors in JavaScript that can silently continue to propagate through your program. We call these “forgiving” errors because they don’t stop script execution, but, despite the innocuous name, we can consider them more dangerous than unforgiving errors because they continue to propagate.
Consider the following JavaScript function:
function subtract(a, b) { return a - b; }
This function might seem straightforward on the surface, but – as the script gets more complex – when variables change and depend on other values spanning thousands of lines of code, you might end up accidentally subtracting a variable that ends up being a number from a variable that ends up being a string. If you attempt such a call, you will get NaN (Not a Number).
Evaluate the following code in your console:
function subtract(a, b) { return a - b; } subtract("a", 1);
Observe the resulting NaN (Not a Number) value. It doesn’t crash your application so we call it a forgiving error, but the error value will propagate throughout the rest of your program so your program continues to silently run with errors. For example, subsequent calculations might depend on the value returned from the ‘subtract’ function. Let’s try additional arithmetic operations to observe:
function subtract(a, b) { return a - b; } var result = subtract("a", 1); // NaN console.log(result); result += 10; // Add 10 to NaN console.log(result);
No crash and no error reports. It just silently continues to run with the error value.
You won’t be able to run the following code, but here’s an illustration of how such error values might propagate through your application in a potential real-world scenario, a shopping cart backend:
var total = 0; total += totalCartItems(); while ((removedPrice = removedFromCart()) != null) { total = subtract(total, removedPrice); } total += tax(); total += shipping();
In the example above, our shopping cart can end up with a NaN (Not a Number) value – resulting in lost sales for the business that can be difficult to detect because there were no explicit errors.
JS++ | Types in JavaScript
In this chapter, we’re going to explore JavaScript programming styles and how developers worked with types in JavaScript (rather than JS++). This chapter will help you understand the next chapters which explain the JS++ type system in detail.
In this tutorial, we will be using the Google Chrome web browser. Click here to download Google Chrome if you don’t already have it.
In order to execute JavaScript code, we’ll be using the Chrome Developer Tools console. Open Chrome and hit the Ctrl + Shift + J key combination and choose the “Console” tab.
Copy and paste the following code into your console and press enter to execute it:
var message; message = "This is a test."; if (Math.random() > 0.5) { message = 123; } console.log(message);
Hit your “up arrow” and hit “enter” to evaluate the code more than once. Try evaluating the code a few times.
Notice how the data type in the above code changes from a string to a number. However, it only changes to a number if a randomly-generated number is greater than 0.5. Therefore, the data type of the variable ‘message’ can be different each time the script is executed. This was a major problem in JavaScript. For example, the following JavaScript code is unsafe:
function lowercaseCompare(a, b) { return a.toLowerCase() == b.toLowerCase(); }
The reason is because toLowerCase() is a method that’s only available to JavaScript strings. Let’s execute the following JavaScript code in the Chrome console:
function lowercaseCompare(a, b) { return a.toLowerCase() == b.toLowerCase(); } console.log("First message."); lowercaseCompare("10", 10); // Crashes with 'TypeError' console.log("Second message."); // Never executes.
Notice how the script will crash with a TypeError. The second message never gets logged. The key takeaway is that the code crashed because toLowerCase() is not a method available for numbers, but the function was called with a string (“10”) and a number (10). The number argument was not a valid argument for the ‘lowercaseCompare’ function. If you change the function call, you will observe that the program no longer crashes:
// Change this: // lowercaseCompare("10", 10); // Crashes with 'TypeError' // to: lowercaseCompare("10", "10");
Developers worked around these problems in JavaScript by checking the types first. This is the safer way to rewrite the above ‘lowercaseCompare’ function in JavaScript:
function lowercaseCompare(a, b) { if (typeof a != "string" || typeof b != "string") { return false; } return a.toLowerCase() == b.toLowerCase(); }
We check the types using ‘typeof’, and, if we receive invalid argument types, we return a default value. However, for larger programs, this can result in a lot of extra code and there may not always be an applicable default value.