Skip to content

Commit a6640e4

Browse files
committed
ch4 copyedits & fix em-dash spacing for full manuscript
1 parent 60a666e commit a6640e4

File tree

7 files changed

+284
-237
lines changed

7 files changed

+284
-237
lines changed

β€Žch03.asciidoc

Lines changed: 70 additions & 66 deletions
Large diffs are not rendered by default.

β€Žch04.asciidoc

Lines changed: 185 additions & 142 deletions
Large diffs are not rendered by default.

β€Žch05.asciidoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ map.has(1)
154154
// <- []
155155
----
156156

157-
Maps come with a read-only `.size` property that behaves similarly to `Array#length` -- at any point in time it gives you the current amount of entries in the map.
157+
Maps come with a read-only `.size` property that behaves similarly to `Array#length`--at any point in time it gives you the current amount of entries in the map.
158158

159159
[source,javascript]
160160
----
@@ -169,7 +169,7 @@ map.size
169169
// <- 0
170170
----
171171

172-
You're able to use arbitrary objects when choosing map keys: you're not limited to using primitive values like symbols, numbers, or strings. Instead, you can use functions, objects, dates -- and even DOM elements, too. Keys won't be cast to strings as we observe with plain JavaScript objects, but instead their references are preserved.
172+
You're able to use arbitrary objects when choosing map keys: you're not limited to using primitive values like symbols, numbers, or strings. Instead, you can use functions, objects, dates--and even DOM elements, too. Keys won't be cast to strings as we observe with plain JavaScript objects, but instead their references are preserved.
173173

174174
[source,javascript]
175175
----
@@ -439,7 +439,7 @@ map.set(Symbol(), 2)
439439
// <- TypeError
440440
----
441441

442-
In exchange for having a more limited feature set, `WeakMap` key references are weakly held, meaning that the objects referenced by `WeakMap` keys are subject to garbage collection if there are no references to them -- other than weak references. This kind of behavior is useful when you have metadata about a `person`, for example, but you want the `person` to be garbage collected when and if the only reference back to `person` is their associated metadata. You can now keep that metadata in a `WeakMap` using `person` as the key.
442+
In exchange for having a more limited feature set, `WeakMap` key references are weakly held, meaning that the objects referenced by `WeakMap` keys are subject to garbage collection if there are no references to them--other than weak references. This kind of behavior is useful when you have metadata about a `person`, for example, but you want the `person` to be garbage collected when and if the only reference back to `person` is their associated metadata. You can now keep that metadata in a `WeakMap` using `person` as the key.
443443

444444
In that sense, a `WeakMap` is most useful when the component maintaining it doesn't own the mapped objects, but wants to assign its own information to them without modifying the original objects or their lifecycle; letting memory be reclaimed when, for example, a DOM node is removed from the document.
445445

@@ -476,7 +476,7 @@ Correspondingly, use cases for `WeakMap` revolve around the need to specify meta
476476

477477
Keeping data about DOM elements that should be released from memory when they're no longer of interest is another important use case, and in this regard using `WeakMap` is an even better solution to the DOM-related API caching solution we implemented earlier using `Map`.
478478

479-
In so many words, then: no, `WeakMap` is definitely not worse than `Map` -- they just cater to different use cases.
479+
In so many words, then: no, `WeakMap` is definitely not worse than `Map`--they just cater to different use cases.
480480

481481
=== Sets in ES6
482482

β€Žch06.asciidoc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Proxies are an interesting and powerful feature in ES6 that act as intermediarie
55

66
=== Getting Started with Proxy
77

8-
By default, proxies don't do much -- in fact they don't do anything. If you don't provide any configuration, your proxy will just work as a pass-through to the `target` object, also known as a "no-op forwarding proxy," meaning that all operations on the proxy object defer to the underlying object.
8+
By default, proxies don't do much--in fact they don't do anything. If you don't provide any configuration, your proxy will just work as a pass-through to the `target` object, also known as a "no-op forwarding proxy," meaning that all operations on the proxy object defer to the underlying object.
99

1010
In the following piece of code, we create a no-op forwarding `Proxy`. You can observe how by assigning a value to `proxy.exposed`, that value is passed onto `target.exposed`. You could think of proxies as the gatekeepers of their underlying objects: they may allow certain operations to go through and prevent others from passing, but they carefully inspect every single interaction with their underlying objects.
1111

@@ -123,7 +123,7 @@ proxy._secret = 'invalidate'
123123
// <- Error: Can't set private "_secret" property
124124
----
125125

126-
The object being proxied, `target` in our latest example, should be completely hidden from consumers, so that they are forced to access it exclusively through `proxy`. Preventing direct access to the `target` object means that they will have to obey the access rules defined on the `proxy` object -- such as _"properties prefixed with an underscore are off-limits."_
126+
The object being proxied, `target` in our latest example, should be completely hidden from consumers, so that they are forced to access it exclusively through `proxy`. Preventing direct access to the `target` object means that they will have to obey the access rules defined on the `proxy` object--such as _"properties prefixed with an underscore are off-limits."_
127127

128128
To that end, you could wrap the proxied object in a function and then return the `proxy`.
129129

@@ -260,7 +260,7 @@ console.log(proxy.isUsable)
260260
// <- TypeError: illegal operation attempted on a revoked proxy
261261
----
262262

263-
This type of `Proxy` is particularly useful because you can completely cut off access to the `proxy` granted to a consumer. You could expose a revocable `Proxy` and keep around the `revoke` method, perhaps in a `WeakMap` collection. When it becomes clear that the consumer shouldn't have access to `target` anymore -- not even through `proxy` -- you `.revoke()` their access rights.
263+
This type of `Proxy` is particularly useful because you can completely cut off access to the `proxy` granted to a consumer. You could expose a revocable `Proxy` and keep around the `revoke` method, perhaps in a `WeakMap` collection. When it becomes clear that the consumer shouldn't have access to `target` anymore--not even through `proxy`--you `.revoke()` their access rights.
264264

265265
The following example shows two functions. The `getStorage` function can be used to get proxied access into `storage`, and it keeps a reference to the `revoke` function for the returned `proxy` object. Whenever we want to cut off access to `storage` for a given `proxy`, `revokeStorage` will call its associated `revoke` function and remove the entry from the `WeakMap`. Note that making both functions accessible to the same set of consumers won't pose security concerns: once access through a proxy has been revoked, it can't be restored.
266266

@@ -286,7 +286,7 @@ Given that `revoke` is available on the same scope where your `handler` traps ar
286286

287287
=== Proxy Trap Handlers
288288

289-
Perhaps the most interesting aspect of proxies is how you can use them to intercept just about any interaction with the `target` object -- not only plain `get` or `set` operations.
289+
Perhaps the most interesting aspect of proxies is how you can use them to intercept just about any interaction with the `target` object--not only plain `get` or `set` operations.
290290

291291
We've already covered `get`, which traps property access; and `set`, which traps property assignment. Next up we'll discuss the different kinds of traps you can set up.
292292

@@ -329,7 +329,7 @@ function invariant(key, action) {
329329
}
330330
----
331331

332-
Note how accessing properties through the proxy will now return `false` when querying one of the private properties, with the consumer being none the wiser -- completely unaware that we've intentionally hid the property from them. Note how `_secret in target` returns `true` because we're bypassing the proxy. That means we can still use the underlying object unchallenged by tight access control rules while consumers have no choice but to stick to the proxy's rules.
332+
Note how accessing properties through the proxy will now return `false` when querying one of the private properties, with the consumer being none the wiser--completely unaware that we've intentionally hid the property from them. Note how `_secret in target` returns `true` because we're bypassing the proxy. That means we can still use the underlying object unchallenged by tight access control rules while consumers have no choice but to stick to the proxy's rules.
333333

334334
[source,javascript]
335335
----
@@ -429,7 +429,7 @@ Consumers interacting with `target` through the `proxy` can no longer delete pro
429429

430430
==== defineProperty Trap
431431

432-
The `Object.defineProperty` function -- introduced in ES5 -- can be used to add new properties to a `target` object, using a property `key` and a property `descriptor`. For the most part, `Object.defineProperty(target, key, descriptor)` is used in two kinds of situations:
432+
The `Object.defineProperty` function--introduced in ES5--can be used to add new properties to a `target` object, using a property `key` and a property `descriptor`. For the most part, `Object.defineProperty(target, key, descriptor)` is used in two kinds of situations:
433433

434434
1. When we need to ensure cross-browser support of getters and setters
435435
2. When we want to define a custom property accessor

β€Žch07.asciidoc

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ console.log(0x0ff) // <- 255
6969
console.log(0xf00) // <- 3840
7070
----
7171

72-
Besides these minor syntax changes where octal and binary literals were introduced, a few methods were added to `Number` in ES6. The first four `Number` methods that we'll be discussing -- `Number.isNaN`, `Number.isFinite`, `Number.parseInt`, and `Number.parseFloat` -- already existed as functions in the global namespace. In addition, the methods in `Number` are slightly different in that they don't coerce nonnumeric values into numbers before producing a result.
72+
Besides these minor syntax changes where octal and binary literals were introduced, a few methods were added to `Number` in ES6. The first four `Number` methods that we'll be discussing--`Number.isNaN`, `Number.isFinite`, `Number.parseInt`, and `Number.parseFloat`--already existed as functions in the global namespace. In addition, the methods in `Number` are slightly different in that they don't coerce nonnumeric values into numbers before producing a result.
7373

7474
==== Number.isNaN
7575

@@ -104,9 +104,9 @@ isNaN(new Date())
104104

105105
`Number.isNaN` is more precise than its global counterpart, because it doesn't involve casting. There are still a few reasons why `Number.isNaN` can be a source of confusion.
106106

107-
First off, `isNaN` casts input through `Number(value)` before comparison, while `Number.isNaN` doesn't. Neither `Number.isNaN` nor `isNaN` answer the "is this not a number?" question, but instead they answer whether `value` -- or `Number(value)` -- is `NaN`.
107+
First off, `isNaN` casts input through `Number(value)` before comparison, while `Number.isNaN` doesn't. Neither `Number.isNaN` nor `isNaN` answer the "is this not a number?" question, but instead they answer whether `value`--or `Number(value)`--is `NaN`.
108108

109-
In most cases, what you actually want to know is whether a value identifies as a number -- `typeof NaN === 'number'` -- and is a number. The `isNumber` function in the following code snippet does just that. Note that it'd work with both `isNaN` and `Number.isNaN` due to type checking. Everything that reports a `typeof` value of `'number'` is a number, except for `NaN`, so we filter out those out as false positive results.
109+
In most cases, what you actually want to know is whether a value identifies as a number--`typeof NaN === 'number'`--and is a number. The `isNumber` function in the following code snippet does just that. Note that it'd work with both `isNaN` and `Number.isNaN` due to type checking. Everything that reports a `typeof` value of `'number'` is a number, except for `NaN`, so we filter out those out as false positive results.
110110

111111
[source,javascript]
112112
----
@@ -137,7 +137,7 @@ There is a function, which was already in the language, that somewhat resembles
137137

138138
The rarely promoted `isFinite` method has been available since ES3. It returns a boolean value indicating whether the provided `value` matches none of: `Infinity`, `-Infinity`, and `NaN`.
139139

140-
The `isFinite` method coerces values through `Number(value)`, while `Number.isFinite` doesn't. This means that values that can be coerced into non-`NaN` numbers will be considered finite numbers by `isNumber` -- even though they aren't explicit numbers.
140+
The `isFinite` method coerces values through `Number(value)`, while `Number.isFinite` doesn't. This means that values that can be coerced into non-`NaN` numbers will be considered finite numbers by `isNumber`--even though they aren't explicit numbers.
141141

142142
Here are a few examples using the global `isFinite` function.
143143

@@ -407,7 +407,7 @@ Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // <- true
407407
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // <- false
408408
----
409409

410-
When we want to verify if the result of an operation is within bounds, we must verify not only the result but also both operands.footnoteref:[math-axel,Dr. Axel Rauschmayer points this out in an article titled "New number and Math features in ES6": https://mjavascript.com/out/math-axel.] One -- or both -- of the operands may be out of bounds, while the result is within bounds but incorrect. Similarly, the result may be out of bounds even if both operands are within bounds. Checking all of `left`, `right`, and the result of `left op right` is, thus, necessary to verify that we can indeed trust the result.
410+
When we want to verify if the result of an operation is within bounds, we must verify not only the result but also both operands.footnoteref:[math-axel,Dr. Axel Rauschmayer points this out in an article titled "New number and Math features in ES6": https://mjavascript.com/out/math-axel.] One--or both--of the operands may be out of bounds, while the result is within bounds but incorrect. Similarly, the result may be out of bounds even if both operands are within bounds. Checking all of `left`, `right`, and the result of `left op right` is, thus, necessary to verify that we can indeed trust the result.
411411

412412
In the following example both operands are within bounds, but the result is incorrect.
413413

@@ -616,7 +616,7 @@ The inverse function of `Math.expm1` is `Math.log1p`.
616616

617617
==== Math.log1p
618618

619-
This is the natural logarithm of `value` plus `1` -- `ln(value + 1)` -- and the inverse function of `Math.expm1`. The base `e` logarithm of a number can be expressed as `Math.log` in JavaScript.
619+
This is the natural logarithm of `value` plus `1`--`ln(value + 1)`--and the inverse function of `Math.expm1`. The base `e` logarithm of a number can be expressed as `Math.log` in JavaScript.
620620

621621
[source,javascript]
622622
----
@@ -637,7 +637,7 @@ Math.log1p(1.00000000005e-10)
637637

638638
==== Math.log10
639639

640-
Base 10 logarithm of a number -- `log~10~(value)`.
640+
Base 10 logarithm of a number--`log~10~(value)`.
641641

642642
[source,javascript]
643643
----
@@ -658,7 +658,7 @@ And then there's `Math.log2`.
658658

659659
==== Math.log2
660660

661-
Base 2 logarithm of a number -- `log~2~(value)`.
661+
Base 2 logarithm of a number--`log~2~(value)`.
662662

663663
[source,javascript]
664664
----
@@ -1080,7 +1080,7 @@ Let's switch protocols and learn about Unicode.
10801080

10811081
==== Unicode
10821082

1083-
JavaScript strings are represented using UTF-16 code units.footnoteref:[unicode-encodings,Learn more about UCS-2, UCS-4, UTF-16, and UTF-32 here: https://mjavascript.com/out/unicode-encodings.] Each code unit can be used to represent a code point in the `[U+0000, U+FFFF]` range -- also known as the BMP, short for Basic Multilingual Plane. You can represent individual code points in the BMP plane using the `'\u3456'` syntax. You could also represent code units in the `[U+0000, U+0255]` range using the `\x00..\xff` notation. For instance, `'\xbb'` represents `'Β»'`, the `U+00BB` code point, as you can also verify by doing `String.fromCharCode(0xbb)`.
1083+
JavaScript strings are represented using UTF-16 code units.footnoteref:[unicode-encodings,Learn more about UCS-2, UCS-4, UTF-16, and UTF-32 here: https://mjavascript.com/out/unicode-encodings.] Each code unit can be used to represent a code point in the `[U+0000, U+FFFF]` range--also known as the BMP, short for Basic Multilingual Plane. You can represent individual code points in the BMP plane using the `'\u3456'` syntax. You could also represent code units in the `[U+0000, U+0255]` range using the `\x00..\xff` notation. For instance, `'\xbb'` represents `'Β»'`, the `U+00BB` code point, as you can also verify by doing `String.fromCharCode(0xbb)`.
10841084

10851085
For code points beyond `U+FFFF`, you'd represent them as a surrogate pair. That is to say, two contiguous code units. For instance, the horse emoji pass:[<code>'<img src="images/1f40e.png" style="width: 12px" alt="🐎" data-emoji-embed="🐎" />'</code>] code point is represented with the `'\ud83d\udc0e'` contiguous code units. In ES6 notation you can also represent code points using the `'\u{1f40e}'` notation (that example is also the horse emoji).
10861086

@@ -1093,7 +1093,7 @@ The `'\ud83d\udc0e\ud83d\udc71\u2764'` string, found in the next code snippet, e
10931093
// &lt;- '<img src="images/1f40e.png" style="width: 12px" alt="🐎" data-emoji-embed="🐎" /><img src="images/1f471.png" style="width: 12px" alt="πŸ‘±" data-emoji-embed="πŸ‘±" /><img src="images/2764.png" style="width: 12px" alt="❀️" data-emoji-embed="❀️" />'</pre>
10941094
++++
10951095

1096-
While that string consists of five code units, we know that the length should really be 3 -- as there are only three emoji.
1096+
While that string consists of five code units, we know that the length should really be 3--as there are only three emoji.
10971097

10981098
++++
10991099
<pre data-type="programlisting" data-code-language="javascript">'\ud83d\udc0e\ud83d\udc71\u2764'.length
@@ -1804,7 +1804,7 @@ console.log(...parseAttributes(html))
18041804
// ]
18051805
----
18061806

1807-
A bigger source of confusion is that `rattributes` mutates its `lastIndex` property on each call to `RegExp#exec`, which is how it can track the position after the last match. When there are no matches left, `lastIndex` is reset back to `0`. A problem arises when we don't iterate over all possible matches for a piece of input in one go -- which would reset `lastIndex` to `0` -- and then we use the regular expression on a second piece of input, obtaining unexpected results.
1807+
A bigger source of confusion is that `rattributes` mutates its `lastIndex` property on each call to `RegExp#exec`, which is how it can track the position after the last match. When there are no matches left, `lastIndex` is reset back to `0`. A problem arises when we don't iterate over all possible matches for a piece of input in one go--which would reset `lastIndex` to `0`--and then we use the regular expression on a second piece of input, obtaining unexpected results.
18081808

18091809
While it looks like our `matchAll` implementation wouldn't fall victim of this given it loops over all matches, it's be possible to iterate over the generator by hand, meaning that we'd run into trouble if we reused the same regular expression, as shown in the next bit of code. Note how the second matcher should report `['type', 'text']` but instead starts at an index much further ahead than `0`, even misreporting the `'placeholder'` key as `'laceholder'`.
18101810

@@ -1957,9 +1957,9 @@ Array.from(document.querySelectorAll('div')).slice(1)
19571957

19581958
`Array.from` has three arguments, although only the `input` is required. To wit:
19591959

1960-
- `input` -- the array-like or iterable object you want to cast
1961-
- `map` -- a mapping function that's executed on every item of `input`
1962-
- `context` -- the `this` binding to use when calling `map`
1960+
- `input`--the array-like or iterable object you want to cast
1961+
- `map`--a mapping function that's executed on every item of `input`
1962+
- `context`--the `this` binding to use when calling `map`
19631963

19641964
With `Array.from` you cannot slice, but you can dice. The `map` function will efficiently map the values into something else as they're being added to the array that results from calling `Array.from`.
19651965

0 commit comments

Comments
Β (0)