Skip to content

Commit e99076b

Browse files
committed
more edits/revisions, adding thank you's in appendix D
1 parent 0f38323 commit e99076b

File tree

5 files changed

+60
-40
lines changed

5 files changed

+60
-40
lines changed

preface.md

+7-13
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,31 @@ From the earliest days of the web, JavaScript has been a foundational technology
77

88
But as a language, it has perpetually been a target for a great deal of criticism, owing partly to its heritage but even more to its design philosophy. Even the name evokes, as Brendan Eich once put it, "dumb kid brother" status next to its more mature older brother "Java". But the name is merely an accident of politics and marketing. The two languages are vastly different in many important ways. "JavaScript" is as related to "Java" as "Carnival" is to "Car".
99

10-
Because JavaScript borrows concepts and syntax idioms from several languages, including proud C-style procedural roots as well as subtle, less obvious Scheme/Lisp-style functional roots, it is exceedingly approachable to a broad audience of developers, even those with just none to little programming experience. The "Hello World" of JavaScript is so simple that the language is inviting and easy to get comfortable with in early exposure.
10+
Because JavaScript borrows concepts and syntax idioms from several languages, including proud C-style procedural roots as well as subtle, less obvious Scheme/Lisp-style functional roots, it is exceedingly approachable to a broad audience of developers, even those with just little to no programming experience. The "Hello World" of JavaScript is so simple that the language is inviting and easy to get comfortable with in early exposure.
1111

1212
While JavaScript is perhaps one of the easiest languages to get up and running with, its eccentricities make solid mastery of the language a vastly less common occurrence than in many other languages. Where it takes a pretty in-depth knowledge of a language like C or C++ to write a full-scale program, full-scale production JavaScript can, and often does, barely scratch the surface of what the language can do.
1313

1414
Sophisticated concepts which are deeply rooted into the language tend instead to surface themselves in *seemingly* simplistic ways, such as passing around functions as callbacks, which encourages the JavaScript developer to just use the language as-is and not worry too much about what's going on under the hood.
1515

1616
It is simultaneously a simple, easy-to-use language that has broad appeal, and a complex and nuanced collection of language mechanics which without careful study will elude *true understanding* even for the most seasoned of JavaScript developers.
1717

18-
But therein lies the paradox of JavaScript, the Achilles' Heel of the language, the challenge we are presently addressing. Because JavaScript *can* be used without understanding, the understanding of the language is often never attained. But this *friendliness* offers no protection to a developer from the binary harshness of the "it works or it doesn't" reality. The language cannot magically do something other than what you tell it to do. If you fail to instruct it correctly, because you do not understand *how* to do so, you will inevitably receive an unexpected (to you, anyway!) result.
18+
Therein lies the paradox of JavaScript, the Achilles' Heel of the language, the challenge we are presently addressing. Because JavaScript *can* be used without understanding, the understanding of the language is often never attained.
1919

20-
And yet, since the language still feels so friendly and unassuming of such nuance, JavaScript developers, and indeed, developers of other languages who grudgingly tolerate the necessity of JS in a project, will not turn first their finger of blame at their own lack of understanding, but instead towards the language itself.
20+
## Mission
2121

22-
Perhaps the most famous indictment (among many!) is aimed squarely at the "implicit coercion" mechanism in JavaScript, and accuses that *feature* of being a design flaw, a bug, a mistake. This criticism, to be fair, targets a part of the language which is littered with many treacherous stumbling blocks. But when you analyze the argument and the mindset, you begin to see that implicit coercion is an intentional and powerful feature like any other, and has both its shining moments and its danger zones which you must be careful around.
23-
24-
To hear this criticism to its full extent, what is argued is that the mechanism is too complex, too fraught with issues and misunderstanding, and rather than trudge through *to* the land of enlightenment, JavaScript developers should simply not travel down that difficult path. It's a textbook case of "throwing the baby out with the bathwater".
25-
26-
While avoiding such pitfalls certainly protects you, the JS developer, from the pain of misstep, it also cuts off at the knees the power and potential of the language and what you can do with it.
27-
28-
And most dangerously of all, it perpetuates in you a mindset which emphasizes avoidance and blame shifting, instead of cheering you on *and assisting you* to deeper and more mature understanding. If at every point that you encounter a surprise or frustration in JavaScript, your response is to add it to the blacklist, you soon will be relegated to a hollow shell of the richness of JavaScript.
22+
If at every point that you encounter a surprise or frustration in JavaScript, your response is to add it to the blacklist, as some are accustomed to doing, you soon will be relegated to a hollow shell of the richness of JavaScript.
2923

3024
While this subset has been famoulsy dubbed "The Good Parts", I would implore you, dear reader, to instead consider it the "The Easy Parts", "The Safe Parts", or even "The Incomplete Parts".
3125

32-
Our "You Don't Know JavaScript" book series offers a contrary challenge: learn and deeply understand *all* of JavaScript, even and especially "The Tough Parts".
26+
This "You Don't Know JavaScript" book series offers a contrary challenge: learn and deeply understand *all* of JavaScript, even and especially "The Tough Parts".
3327

34-
Here, we address head on the tendency of JS developers not only to learn "just enough" to get by, without ever forcing themselves to learn exactly how and why the language behaves the way it does, but we eschew the common advice to *retreat* when the road gets rough.
28+
Here, we address head on the tendency of JS developers to learn "just enough" to get by, without ever forcing themselves to learn exactly how and why the language behaves the way it does. Furthermore, we eschew the common advice to *retreat* when the road gets rough.
3529

3630
I am not content, nor should you be, at stopping once something *just works*, and not really knowing *why*. I gently challenge you to journey down that bumpy "road less traveled" and embrace all that JavaScript is and can do. With that knowledge, no technique, no framework, no popular buzzword acronym of the week, will be beyond your understanding.
3731

3832
These books each take on specific core parts of the language which are most commonly misunderstood or under-understood, and dive very deep and exhaustively into them. You should come away from reading with a firm confidence in your understanding, not just of the theoretical, but the practical "what you need to know" bits.
3933

40-
The JavaScript you know *right now* is probably *parts* handed down to you by others tending to and bandaging their battle scars. *That* JavaScript is but a shadow of the true language. You don't *really* know JavaScript, *yet*, but if you dig into this series, you *will*. Read on, my friends. JavaScript awaits you.
34+
The JavaScript you know *right now* is probably *parts* handed down to you by others who've been burned by incomplete understanding. *That* JavaScript is but a shadow of the true language. You don't *really* know JavaScript, *yet*, but if you dig into this series, you *will*. Read on, my friends. JavaScript awaits you.
4135

4236
## Review (TL;DR)
4337

scope & closures/apA.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# You Don't Know JS: Scope & Closures
22
# Appendix A: Dynamic Scope
33

4-
In Chapter 2, I mentioned "Dynamic Scope" as a contrast to how scope works in JavaScript (and in fact, most other languages): Lexical Scope.
4+
In Chapter 2, we talked about "Dynamic Scope" as a contrast to the "Lexical Scope" model, which is how scope works in JavaScript (and in fact, most other languages).
55

6-
We will briefly examine dynamic scope, to hammer home the contrast. But, more importantly, dynamic scope actually is a near cousin to another mechanism in JavaScript, which we will not cover in this title but *do* cover in the "*this & Object Prototypes*" title: `this`.
6+
We will briefly examine dynamic scope, to hammer home the contrast. But, more importantly, dynamic scope actually is a near cousin to another mechanism (`this`) in JavaScript, which we is covered in the "*this & Object Prototypes*" title.
77

8-
As we saw in Chapter 2, lexical scope is the set of rules about how the *Engine* can look-up a variable and where it will find it. The key characteristic of lexical scope is that it is defined at author-time, when the code is written (assuming you don't cheat with `eval()` and `with`).
8+
As we saw in Chapter 2, lexical scope is the set of rules about how the *Engine* can look-up a variable and where it will find it. The key characteristic of lexical scope is that it is defined at author-time, when the code is written (assuming you don't cheat with `eval()` or `with`).
99

1010
Dynamic scope seems to imply, and for good reason, that there's a model whereby scope can be determined dynamically at runtime, rather than statically at author-time. That is in fact the case. Let's illustrate via code:
1111

@@ -26,7 +26,7 @@ bar();
2626

2727
Lexical scope holds that the RHS reference to `a` in `foo()` will be resolved to the global variable `a`, which will result in value `2` being output.
2828

29-
Dynamic scope, by contrast, doesn't concern itself with how and where functions and scopes are declared, but rather *where they are called from*. In other words, the scope chain is based on the call-stack, not the nesting of scopes in code.
29+
Dynamic scope, by contrast, doesn't concern itself with how and where functions and scopes are declared, but rather **where they are called from**. In other words, the scope chain is based on the call-stack, not the nesting of scopes in code.
3030

3131
So, if JavaScript had dynamic scope, when `foo()` is executed, **theoretically** the code below would instead result in `3` as the output.
3232

@@ -47,10 +47,12 @@ bar();
4747

4848
How can this be? Because when `foo()` cannot resolve the variable reference for `a`, instead of stepping up the nested (lexical) scope chain, it walks up the call-stack, to find where `foo()` was *called from*. Since `foo()` was called from `bar()`, it checks the variables in scope for `bar()`, and finds an `a` there with value `3`.
4949

50-
Strange? Probably you're thinking so, at the moment.
50+
Strange? You're probably thinking so, at the moment.
5151

5252
But that's just because you've probably only ever worked on (or at least deeply considered) code which is lexically scoped. So dynamic scoping seems foreign. If you had only ever written code in a dynamically scoped language, it would seem natural, and lexical scope would be the odd-ball.
5353

5454
To be clear, JavaScript **does not, in fact, have dynamic scope**. It has lexical scope. Plain and simple. But the `this` mechanism is kind of like dynamic scope.
5555

56-
The key contrast: **lexical scope is write-time, whereas dynamic scope (and `this`!) are runtime**. Lexical scope cares *where a function was declared*, dynamic scope cares where a function was *called from*, and `this` cares *how a function was called*. To dig more into `this`, read the title "*this & Object Prototypes*".
56+
The key contrast: **lexical scope is write-time, whereas dynamic scope (and `this`!) are runtime**. Lexical scope cares *where a function was declared*, but dynamic scope cares where a function was *called from*.
57+
58+
Finally: `this` cares *how a function was called*, which shows how closely related the `this` mechanism is to the idea of dynamic scoping. To dig more into `this`, read the title "*this & Object Prototypes*".

scope & closures/apB.md

+17-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
In Chapter 3, we explored Block Scope. We saw that `with` and the `catch` clause are both tiny examples of block scope that have existed in JavaScript since at least the introduction of ES3.
55

6-
But it's ES6's introduction of `let` that finally gives full, unfettered block-scoping capability to our code. There are many exciting things, both functionally and code stylistically, that block scope will enable.
6+
But it's ES6's introduction of `let` that finally gives full, unfettered block-scoping capability to our code. There are many exciting things, both functionally and code-stylistically, that block scope will enable.
77

88
But what if we wanted to use block scope in pre-ES6 environments?
99

@@ -28,7 +28,7 @@ try{throw 2}catch(a){
2828
console.log( a ); // ReferenceError
2929
```
3030

31-
Whoa, man! That's some ugly, weird looking code. We see a `try/catch` that appears to forcibly throw an error, but the "error" it throws is just a value `2`, and then the variable declaration that receives it is in the `catch(a)` clause. Mind blown.
31+
Whoa! That's some ugly, weird looking code. We see a `try/catch` that appears to forcibly throw an error, but the "error" it throws is just a value `2`, and then the variable declaration that receives it is in the `catch(a)` clause. Mind: blown.
3232

3333
That's right, the `catch` clause has block-scoping to it, which means it can be used as a polyfill for block scope in pre-ES6 environments.
3434

@@ -79,9 +79,21 @@ As a pattern, it mirrors the approach many people take in function-scoping when
7979

8080
But, there's a problem. The let-statement form is not included in ES6. Neither does the official Traceur compiler accept that form of code.
8181

82-
Tools are meant to solve our problems. So, I built a tool called "let-er" [^note-let_er] to address just this issue. *let-er* is a build-step code transpiler, but its only task is to find let-statement forms and transpile them. It will leave alone any of the rest of your code, including any let-declarations. You can safely use *let-er* as the first ES6 transpiler step, and then pass your code through something like Traceur if necessary.
82+
We have two options. We can format using ES6-valid syntax and a little sprinkle of code discipline:
8383

84-
Moreover, *let-er* has a configuration flag `--es6`, which when turned on, changes the kind of code produced. Instead of the `try/catch` ES3 polyfill hack, *let-er* would take our snippet and produce the fully ES6-compliant, non-hacky:
84+
```js
85+
/*let*/ { let a = 2;
86+
console.log( a );
87+
}
88+
89+
console.log( a ); // ReferenceError
90+
```
91+
92+
But, tools are meant to solve our problems. So the other option is to write explicit let statement blocks, and let a tool convert them to valid, working code.
93+
94+
So, I built a tool called "let-er" [^note-let_er] to address just this issue. *let-er* is a build-step code transpiler, but its only task is to find let-statement forms and transpile them. It will leave alone any of the rest of your code, including any let-declarations. You can safely use *let-er* as the first ES6 transpiler step, and then pass your code through something like Traceur if necessary.
95+
96+
Moreover, *let-er* has a configuration flag `--es6`, which when turned on (off by default), changes the kind of code produced. Instead of the `try/catch` ES3 polyfill hack, *let-er* would take our snippet and produce the fully ES6-compliant, non-hacky:
8597

8698
```js
8799
{
@@ -94,7 +106,7 @@ console.log( a ); // ReferenceError
94106

95107
So, you can start using *let-er* right away, and target all pre-ES6 environments, and when you only care about ES6, you can add the flag and instantly target only ES6.
96108

97-
And most importantly, you can use the more preferable let-statement form even though it is not an official part of any ES version (yet).
109+
And most importantly, **you can use the more preferable and more explicit let-statement form** even though it is not an official part of any ES version (yet).
98110

99111
## Performance
100112

scope & closures/apC.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Briefly, this code suffers a problem:
2323

2424
var obj = {
2525
id: "awesome",
26-
cool: function() {
26+
cool: function coolFn() {
2727
console.log( this.id );
2828
}
2929
};
@@ -42,11 +42,11 @@ That might look like:
4242
```js
4343
var obj = {
4444
count: 0,
45-
cool: function() {
45+
cool: function coolFn() {
4646
var self = this;
4747

4848
if (self.count < 1) {
49-
setTimeout( function(){
49+
setTimeout( function timer(){
5050
self.count++;
5151
console.log( "awesome?" );
5252
}, 100 );
@@ -66,10 +66,8 @@ The ES6 solution, the arrow-function, introduces a behavior called "lexical this
6666
```js
6767
var obj = {
6868
count: 0,
69-
cool: function() {
70-
var self = this;
71-
72-
if (self.count < 1) {
69+
cool: function coolFn() {
70+
if (this.count < 1) {
7371
setTimeout( () => { // arrow-function ftw?
7472
this.count++;
7573
console.log( "awesome?" );
@@ -87,17 +85,19 @@ So, in that snippet, the arrow-function doesn't get its `this` unbound in some u
8785

8886
While this makes for shorter code, my perspective is that arrow-functions are really just codifying into the language syntax a common *mistake* of developers, which is to confuse and conflate "this binding" rules with "lexical scope" rules.
8987

90-
A more appropriate approach, in my perspective, to this "problem", is to use the `this` mechanism correctly.
88+
Put another way: why go to the trouble and verbosity of using the `this` style coding paradigm, only to cut it off at the knees by mixing it with lexical references. It seems natural to embrace one approach or the other for any given piece of code, and not mix them in the same piece of code.
89+
90+
**Note:** one other detraction from arrow-functions is that they are anonymous, not named. See Chapter 3 for the reasons why anonymous functions are less desirable than named functions.
91+
92+
A more appropriate approach, in my perspective, to this "problem", is to use and embrace the `this` mechanism correctly.
9193

9294
```js
9395
var obj = {
9496
count: 0,
95-
cool: function() {
96-
var self = this;
97-
98-
if (self.count < 1) {
99-
setTimeout( function(){
100-
this.count++;
97+
cool: function coolFn() {
98+
if (this.count < 1) {
99+
setTimeout( function timer(){
100+
this.count++; // `this` is safe because of `bind(..)`
101101
console.log( "more awesome" );
102102
}.bind( this ), 100 ); // look, `bind()`!
103103
}

0 commit comments

Comments
 (0)