You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 08_error.md
+19-15Lines changed: 19 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,21 +14,21 @@ quote}}
14
14
15
15
Flaws in computer programs are usually called _((bug))s_. It makes programmers feel good to imagine them as little things that just happen to crawl into our work. In reality, of course, we put them there ourselves.
16
16
17
-
If a program is crystallized thought, you can roughly categorize bugs into those caused by the thoughts being confused and those caused by mistakes introduced while converting a thought to code. The former type is generally harder to diagnose and fix than the latter.
17
+
If a program is crystallized thought, we can roughly categorize bugs into those caused by the thoughts being confused and those caused by mistakes introduced while converting a thought to code. The former type is generally harder to diagnose and fix than the latter.
18
18
19
19
## Language
20
20
21
21
{{index parsing, analysis}}
22
22
23
-
Many mistakes could be pointed out to us automatically by the computer, if it knew enough about what we're trying to do. But here JavaScript's looseness is a hindrance. Its concept of bindings and properties is vague enough that it will rarely catch ((typo))s before actually running the program. And even then, it allows you to do some clearly nonsensical things without complaint, such as computing `true * "monkey"`.
23
+
Many mistakes could be pointed out to us automatically by the computer, if it knew enough about what we're trying to do. But here JavaScript's looseness is a hindrance. Its concept of bindings and properties is vague enough that it will rarely catch ((typo))s before actually running the program. Even then, it allows you to do some clearly nonsensical things without complaint, such as computing `true * "monkey"`.
24
24
25
25
{{index [syntax, error], [property, access]}}
26
26
27
27
There are some things that JavaScript does complain about. Writing a program that does not follow the language's ((grammar)) will immediately make the computer complain. Other things, such as calling something that's not a function or looking up a property on an ((undefined)) value, will cause an error to be reported when the program tries to perform the action.
28
28
29
29
{{index NaN, error}}
30
30
31
-
But often, your nonsense computation will merely produce `NaN` (not a number) or an undefined value, while the program happily continues, convinced that it's doing something meaningful. The mistake will manifest itself only later, after the bogus value has traveled through several functions. It might not trigger an error at all but silently cause the program's output to be wrong. Finding the source of such problems can be difficult.
31
+
Often, however, your nonsense computation will merely produce `NaN` (not a number) or an undefined value, while the program happily continues, convinced that it's doing something meaningful. The mistake will manifest itself only later, after the bogus value has traveled through several functions. It might not trigger an error at all but silently cause the program's output to be wrong. Finding the source of such problems can be difficult.
32
32
33
33
The process of finding mistakes—bugs—in programs is called _((debugging))_.
34
34
@@ -38,7 +38,7 @@ The process of finding mistakes—bugs—in programs is called _((debugging))_.
38
38
39
39
{{indexsee "use strict", "strict mode"}}
40
40
41
-
JavaScript can be made a _little_ stricter by enabling _strict mode_. This is done by putting the string `"use strict"` at the top of a file or a function body. Here's an example:
41
+
JavaScript can be made a _little_ stricter by enabling _strict mode_. This can done by putting the string `"use strict"` at the top of a file or a function body. Here's an example:
42
42
43
43
```{test: "error \"ReferenceError: counter is not defined\""}
44
44
function canYouSpotTheProblem() {
@@ -52,6 +52,10 @@ canYouSpotTheProblem();
52
52
// → ReferenceError: counter is not defined
53
53
```
54
54
55
+
{{index ECMAScript, compatibility}}
56
+
57
+
Code inside classes and modules (which we will discuss in [Chapter ?](modules)) is automatically strict. The old non-strict behavior still exists only because some old code might depend on it, and the language designers work hard to avoid breaking any existing programs.
58
+
55
59
{{index "let keyword", [binding, global]}}
56
60
57
61
Normally, when you forget to put `let` in front of your binding, as with `counter` in the example, JavaScript quietly creates a global binding and uses that. In strict mode, an ((error)) is reported instead. This is very helpful. It should be noted, though, that this doesn't work when the binding in question already exists somewhere in scope. In that case, the loop will still quietly overwrite the value of the binding.
@@ -71,7 +75,7 @@ console.log(name);
71
75
72
76
{{index error}}
73
77
74
-
So the bogus call to `Person` succeeded but returned an undefined value and created the global binding `name`. In strict mode, the result is different.
78
+
The bogus call to `Person` succeeded but returned an undefined value and created the global binding `name`. In strict mode, the result is different.
75
79
76
80
```{test: "error \"TypeError: Cannot set properties of undefined (setting 'name')\""}
77
81
"use strict";
@@ -196,7 +200,7 @@ Even if you see the problem already, pretend for a moment that you don't. We kno
196
200
197
201
{{index "trial and error"}}
198
202
199
-
This is where you must resist the urge to start making random changes to the code to see whether that makes it better. Instead, _think_. Analyze what is happening and come up with a ((theory)) of why it might be happening. Then, make additional observations to test this theory—or, if you don't yet have a theory, make additional observations to help you come up with one.
203
+
This is where you must resist the urge to start making random changes to the code to see whether that makes it better. Instead, _think_. Analyze what is happening and come up with a ((theory)) of why it might be happening. Then make additional observations to test this theory—or, if you don't yet have a theory, make additional observations to help you come up with one.
@@ -219,7 +223,7 @@ _Right_. Dividing 13 by 10 does not produce a whole number. Instead of `n /= bas
219
223
220
224
An alternative to using `console.log` to peek into the program's behavior is to use the _debugger_ capabilities of your browser. Browsers come with the ability to set a _((breakpoint))_ on a specific line of your code. When the execution of the program reaches a line with a breakpoint, it is paused, and you can inspect the values of bindings at that point. I won't go into details, as debuggers differ from browser to browser, but look in your browser's ((developer tools)) or search the Web for instructions.
221
225
222
-
Another way to set a breakpoint is to include a `debugger` statement (consisting of simply that keyword) in your program. If the ((developer tools)) of your browser are active, the program will pause whenever it reaches such a statement.
226
+
Another way to set a breakpoint is to include a `debugger` statement (consisting simply of that keyword) in your program. If the ((developer tools)) of your browser are active, the program will pause whenever it reaches such a statement.
223
227
224
228
## Error propagation
225
229
@@ -229,15 +233,15 @@ Not all problems can be prevented by the programmer, unfortunately. If your prog
229
233
230
234
{{index "error recovery"}}
231
235
232
-
If you're programming only for yourself, you can afford to just ignore such problems until they occur. But if you build something that is going to be used by anybody else, you usually want the program to do better than just crash. Sometimes the right thing to do is take the bad input in stride and continue running. In other cases, it is better to report to the user what went wrong and then give up. But in either situation, the program has to actively do something in response to the problem.
236
+
If you're programming only for yourself, you can afford to just ignore such problems until they occur. But if you build something that is going to be used by anybody else, you usually want the program to do better than just crash. Sometimes the right thing to do is take the bad input in stride and continue running. In other cases, it is better to report to the user what went wrong and then give up. In either situation the program has to actively do something in response to the problem.
233
237
234
238
{{index "promptNumber function", validation}}
235
239
236
240
Say you have a function `promptNumber` that asks the user for a number and returns it. What should it return if the user inputs "orange"?
One option is to make it return a special value. Common choices for such values are `null`, `undefined`, or -1.
244
+
One option is to make it return a special value. Common choices for such values are `null`, `undefined`, or `-1`.
241
245
242
246
```{test: no}
243
247
function promptNumber(question) {
@@ -267,7 +271,7 @@ function lastElement(array) {
267
271
268
272
{{index "special return value", readability}}
269
273
270
-
The second issue with returning special values is that it can lead to awkward code. If a piece of code calls `promptNumber` 10 times, it has to check 10 times whether `null` was returned. And if its response to finding `null` is to simply return `null` itself, callers of the function will in turn have to check for it, and so on.
274
+
The second issue with returning special values is that it can lead to awkward code. If a piece of code calls `promptNumber` 10 times, it has to check 10 times whether `null` was returned. If its response to finding `null` is to simply return `null` itself, callers of the function will in turn have to check for it, and so on.
271
275
272
276
## Exceptions
273
277
@@ -277,7 +281,7 @@ When a function cannot proceed normally, what we would often _like_ to do is jus
Exceptions are a mechanism that makes it possible for code that runs into a problem to _raise_ (or _throw_) an exception. An exception can be any value. Raising one somewhat resembles a super-charged return from a function: it jumps out of not just the current function but also its callers, all the way down to the first call that started the current execution. This is called _((unwinding the stack))_. You may remember the stack of function calls that was mentioned in [Chapter ?](functions#stack). An exception zooms down this stack, throwing away all the call contexts it encounters.
284
+
Exceptions are a mechanism that makes it possible for code that runs into a problem to _raise_ (or _throw_) an exception. An exception can be any value. Raising one somewhat resembles a super-charged return from a function: it jumps out of not just the current function but also its callers, all the way down to the first call that started the current execution. This is called _((unwinding the stack))_. You may remember the stack of function calls mentioned in [Chapter ?](functions#stack). An exception zooms down this stack, throwing away all the call contexts it encounters.
@@ -333,7 +337,7 @@ This means when code has several side effects, even if its "regular" control flo
333
337
334
338
{{index "banking example"}}
335
339
336
-
Here is some really bad banking code.
340
+
Here is some really bad banking code:
337
341
338
342
```{includeCode: true}
339
343
const accounts = {
@@ -367,7 +371,7 @@ One way to address this is to use fewer side effects. Again, a programming style
367
371
368
372
{{index block, "try keyword", "finally keyword"}}
369
373
370
-
But that isn't always practical. So there is another feature that `try` statements have. They may be followed by a `finally` block either instead of or in addition to a `catch` block. A `finally` block says "no matter _what_ happens, run this code after trying to run the code in the `try` block."
374
+
Since that isn't always practical, `try` statements have another feature: they may be followed by a `finally` block either instead of or in addition to a `catch` block. A `finally` block says "no matter _what_ happens, run this code after trying to run the code in the `try` block."
The `for (;;)` construct is a way to intentionally create a loop that doesn't terminate on its own. We break out of the loop only when a valid direction is given. _But_ we misspelled `promptDirection`, which will result in an "undefined variable" error. Because the `catch` block completely ignores its exception value (`e`), assuming it knows what the problem is, it wrongly treats the binding error as indicating bad input. Not only does this cause an infinite loop, it "buries" the useful error message about the misspelled binding.
445
+
The `for (;;)` construct is a way to intentionally create a loop that doesn't terminate on its own. We break out of the loop only when a valid direction is given. Unfortunately, we misspelled `promptDirection`, which will result in an "undefined variable" error. Because the `catch` block completely ignores its exception value (`e`), assuming it knows what the problem is, it wrongly treats the binding error as indicating bad input. Not only does this cause an infinite loop, it "buries" the useful error message about the misspelled binding.
442
446
443
447
As a general rule, don't blanket-catch exceptions unless it is for the purpose of "routing" them somewhere—for example, over the network to tell another system that our program crashed. And even then, think carefully about how you might be hiding information.
444
448
445
449
{{index "exception handling"}}
446
450
447
-
So we want to catch a _specific_ kind of exception. We can do this by checking in the `catch` block whether the exception we got is the one we are interested in and rethrowing it otherwise. But how do we recognize an exception?
451
+
We want to catch a _specific_ kind of exception. We can do this by checking in the `catch` block whether the exception we got is the one we are interested in, and if not, rethrow it. But how do we recognize an exception?
448
452
449
453
We could compare its `message` property against the ((error)) message we happen to expect. But that's a shaky way to write code—we'd be using information that's intended for human consumption (the message) to make a programmatic decision. As soon as someone changes (or translates) the message, the code will stop working.
0 commit comments