Skip to content

Commit

Permalink
scope and closures: fixing uncaught typos
Browse files Browse the repository at this point in the history
  • Loading branch information
getify committed Mar 4, 2020
1 parent f77bc4b commit a817865
Show file tree
Hide file tree
Showing 6 changed files with 8 additions and 8 deletions.
4 changes: 2 additions & 2 deletions scope-closures/apA.md
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ function commitAction() {

Here, `result` is clearly only used inside the block, so we use `let`. But `done` is a bit different. It's only useful for the loop, but the `while` clause cannot see `let` declarations that appear inside the loop. So we compromise and use `var`, so that `done` is hoisted to the outer scope where it can be seen.

The alternative—declaring `done` outside the loop—separates it from where it's first used, and either neccesitates picking a default value to assign, or worse, leaving it unassigned and thus looking ambiguous to the reader. I think `var` inside the loop is preferable here.
The alternative—declaring `done` outside the loop—separates it from where it's first used, and either necessitates picking a default value to assign, or worse, leaving it unassigned and thus looking ambiguous to the reader. I think `var` inside the loop is preferable here.

Another helpful characteristic of `var` is seen with declarations inside unintended blocks. Unintended blocks are blocks that are created because the syntax requires a block, but where the intent of the developer is not really to create a localized scope. The best illustration of unintended scope is the `try..catch` statement:

Expand Down Expand Up @@ -726,7 +726,7 @@ I'm perfectly fine with re-using variables for multiple purposes throughout a fu

Again, sadly, `let` cannot do this.

There are other nuances and scenarios when `var` turns out to offer some assistance, but I'm not going to belabor the point any further. The takeaway is that `var` can be useful in our programs alongside `let` (and the occassional `const`). Are you willing to creatively use the tools the JS language provides to tell a richer story to your readers?
There are other nuances and scenarios when `var` turns out to offer some assistance, but I'm not going to belabor the point any further. The takeaway is that `var` can be useful in our programs alongside `let` (and the occasional `const`). Are you willing to creatively use the tools the JS language provides to tell a richer story to your readers?

Don't just throw away a useful tool like `var` because someone shamed you into thinking it wasn't cool anymore. Don't avoid `var` because you got confused once years ago. Learn these tools and use them each for what they're best at.

Expand Down
2 changes: 1 addition & 1 deletion scope-closures/apB.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Remember Figure 2 from back in Chapter 2?
<br><br>
</figure>

This exercise asks you to write a program—any program!—that contains nested functions and block scopes, which satisifies these constraints:
This exercise asks you to write a program—any program!—that contains nested functions and block scopes, which satisfies these constraints:

* If you color all the scopes (including the global scope!) different colors, you need at least six colors. Make sure to add a code comment labeling each scope with its color.

Expand Down
2 changes: 1 addition & 1 deletion scope-closures/ch4.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Different JS environments handle the scopes of your programs, especially the glo

### Browser "Window"

With resepct to treatment of the global scope, the most *pure* environment JS can be run in is as a standalone .js file loaded in a web page environment in a browser. I don't mean "pure" as in nothing automatically added—lots may be added!—but rather in terms of minimal intrusion on the code or interference with its expected global scope behavior.
With respect to treatment of the global scope, the most *pure* environment JS can be run in is as a standalone .js file loaded in a web page environment in a browser. I don't mean "pure" as in nothing automatically added—lots may be added!—but rather in terms of minimal intrusion on the code or interference with its expected global scope behavior.

Consider this .js file:

Expand Down
4 changes: 2 additions & 2 deletions scope-closures/ch5.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ The result of this program is that a `ReferenceError` is thrown on the first lin

| NOTE: |
| :--- |
| The error message as seen here used to be much more vague or misleading. Thankfully, several of us in the community were successfully able to lobby for JS engines to improve this error message so it more accruately tells you what's wrong! |
| The error message as seen here used to be much more vague or misleading. Thankfully, several of us in the community were successfully able to lobby for JS engines to improve this error message so it more accurately tells you what's wrong! |

That error message is quite indicative of what's wrong: `studentName` exists on line 1, but it's not been initialized, so it cannot be used yet. Let's try this:

Expand Down Expand Up @@ -571,7 +571,7 @@ var studentName = "Kyle";

What's going to happen with the first `console.log(..)` statement? If `let studentName` didn't hoist to the top of the scope, then the first `console.log(..)` *should* print `"Kyle"`, right? At that moment, it would seem, only the outer `studentName` exists, so that's the variable `console.log(..)` should access and print.

But instead, the first `console.log(..)` throws a TDZ error, because in fact, the inner scope's `studentName` **was** hoisted (auto-registered at the top of the scope). What **didn't** happen (yet!) was the auto-initialization of that inner `studentName`; it's still unintialized at that moment, hence the TDZ violation!
But instead, the first `console.log(..)` throws a TDZ error, because in fact, the inner scope's `studentName` **was** hoisted (auto-registered at the top of the scope). What **didn't** happen (yet!) was the auto-initialization of that inner `studentName`; it's still uninitialized at that moment, hence the TDZ violation!

So to summarize, TDZ errors occur because `let`/`const` declarations *do* hoist their declarations to the top of their scopes, but unlike `var`, they defer the auto-initialization of their variables until the moment in the code's sequencing where the original declaration appeared. This window of time (hint: temporal), whatever its length, is the TDZ.

Expand Down
2 changes: 1 addition & 1 deletion scope-closures/ch6.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ catch { // catch-declaration omitted
}
```

This is a small but delightful simplification of syntax for a fairly common use case, and may also be slightly more performant in removing an unncessary scope!
This is a small but delightful simplification of syntax for a fairly common use case, and may also be slightly more performant in removing an unnecessary scope!

## Function Declarations in Blocks (FiB)

Expand Down
2 changes: 1 addition & 1 deletion scope-closures/ch8.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ var Utils = {
};
```

`Utils` here is a useful collection of utilities, yet they're all state-independent functions. Gathering functionality together is generally good pratice, but that doesn't make this a module. Rather, we've defined a `Utils` namespace and organized the functions under it.
`Utils` here is a useful collection of utilities, yet they're all state-independent functions. Gathering functionality together is generally good practice, but that doesn't make this a module. Rather, we've defined a `Utils` namespace and organized the functions under it.

### Data Structures (Stateful Grouping)

Expand Down

0 comments on commit a817865

Please sign in to comment.