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: ch05.asciidoc
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -154,7 +154,7 @@ map.has(1)
154
154
// <- []
155
155
----
156
156
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.
158
158
159
159
[source,javascript]
160
160
----
@@ -169,7 +169,7 @@ map.size
169
169
// <- 0
170
170
----
171
171
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.
173
173
174
174
[source,javascript]
175
175
----
@@ -439,7 +439,7 @@ map.set(Symbol(), 2)
439
439
// <- TypeError
440
440
----
441
441
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.
443
443
444
444
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.
445
445
@@ -476,7 +476,7 @@ Correspondingly, use cases for `WeakMap` revolve around the need to specify meta
476
476
477
477
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`.
478
478
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.
Copy file name to clipboardExpand all lines: ch06.asciidoc
+6-6Lines changed: 6 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ Proxies are an interesting and powerful feature in ES6 that act as intermediarie
5
5
6
6
=== Getting Started with Proxy
7
7
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.
9
9
10
10
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.
11
11
@@ -123,7 +123,7 @@ proxy._secret = 'invalidate'
123
123
// <- Error: Can't set private "_secret" property
124
124
----
125
125
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."_
127
127
128
128
To that end, you could wrap the proxied object in a function and then return the `proxy`.
129
129
@@ -260,7 +260,7 @@ console.log(proxy.isUsable)
260
260
// <- TypeError: illegal operation attempted on a revoked proxy
261
261
----
262
262
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.
264
264
265
265
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.
266
266
@@ -286,7 +286,7 @@ Given that `revoke` is available on the same scope where your `handler` traps ar
286
286
287
287
=== Proxy Trap Handlers
288
288
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.
290
290
291
291
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.
292
292
@@ -329,7 +329,7 @@ function invariant(key, action) {
329
329
}
330
330
----
331
331
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.
333
333
334
334
[source,javascript]
335
335
----
@@ -429,7 +429,7 @@ Consumers interacting with `target` through the `proxy` can no longer delete pro
429
429
430
430
==== defineProperty Trap
431
431
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:
433
433
434
434
1. When we need to ensure cross-browser support of getters and setters
435
435
2. When we want to define a custom property accessor
Copy file name to clipboardExpand all lines: ch07.asciidoc
+14-14Lines changed: 14 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -69,7 +69,7 @@ console.log(0x0ff) // <- 255
69
69
console.log(0xf00) // <- 3840
70
70
----
71
71
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.
73
73
74
74
==== Number.isNaN
75
75
@@ -104,9 +104,9 @@ isNaN(new Date())
104
104
105
105
`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.
106
106
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`.
108
108
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.
110
110
111
111
[source,javascript]
112
112
----
@@ -137,7 +137,7 @@ There is a function, which was already in the language, that somewhat resembles
137
137
138
138
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`.
139
139
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.
141
141
142
142
Here are a few examples using the global `isFinite` function.
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.
411
411
412
412
In the following example both operands are within bounds, but the result is incorrect.
413
413
@@ -616,7 +616,7 @@ The inverse function of `Math.expm1` is `Math.log1p`.
616
616
617
617
==== Math.log1p
618
618
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.
620
620
621
621
[source,javascript]
622
622
----
@@ -637,7 +637,7 @@ Math.log1p(1.00000000005e-10)
637
637
638
638
==== Math.log10
639
639
640
-
Base 10 logarithm of a number -- `log~10~(value)`.
640
+
Base 10 logarithm of a number--`log~10~(value)`.
641
641
642
642
[source,javascript]
643
643
----
@@ -658,7 +658,7 @@ And then there's `Math.log2`.
658
658
659
659
==== Math.log2
660
660
661
-
Base 2 logarithm of a number -- `log~2~(value)`.
661
+
Base 2 logarithm of a number--`log~2~(value)`.
662
662
663
663
[source,javascript]
664
664
----
@@ -1080,7 +1080,7 @@ Let's switch protocols and learn about Unicode.
1080
1080
1081
1081
==== Unicode
1082
1082
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)`.
1084
1084
1085
1085
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).
1086
1086
@@ -1093,7 +1093,7 @@ The `'\ud83d\udc0e\ud83d\udc71\u2764'` string, found in the next code snippet, e
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.
1808
1808
1809
1809
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'`.
`Array.from` has three arguments, although only the `input` is required. To wit:
1959
1959
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`
1963
1963
1964
1964
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`.
0 commit comments