diff --git a/ch01.asciidoc b/ch01.asciidoc
index 93701bc..fac8b29 100644
--- a/ch01.asciidoc
+++ b/ch01.asciidoc
@@ -53,7 +53,7 @@ Firefox, Chrome, Edge, Safari, and Node.js all offer over 95% compliance of the
The new process involves four different maturity stages.pass:[Take a look at the TC39 proposal process documentation.] The more mature a proposal is, the more likely it is to eventually make it into the specification.
-Any ((("ES6 maturity stages")))((("proposal stages")))discussion, idea, or proposal for a change or addition that has not yet been submitted as a formal proposal is considered to be an aspirational "strawman" proposal (stage 0), but only ((("TC39 standards committee", startref="tc391")))TC39 members can create strawman proposals. At the time of this writing, there are over a dozen active strawman proposals.pass:[You can track strawman proposals.]
+Any ((("ES6 maturity stages")))((("proposal stages")))discussion, idea, or proposal for a change or addition that has not yet been submitted as a formal proposal is considered to be an aspirational "strawman" proposal (stage 0), but only ((("TC39 standards committee", startref="tc391")))TC39 members can create strawman proposals. At the time of this writing, there are over a dozen active strawman proposals.pass:[ You can track strawman proposals.]
At stage 1 a proposal is formalized and expected to address cross-cutting concerns, interactions with other proposals, and implementation concerns. Proposals at this stage should identify a discrete problem and offer a concrete solution to the problem. A stage 1 proposal often includes a high-level API description, illustrative usage examples, and a discussion of internal semantics and algorithms. Stage 1 proposals are likely to change significantly as they make their way through the process.
@@ -85,7 +85,7 @@ Let's talk about how you can use Babel as part of your workflow.
Babel can compile modern JavaScript code that relies on ES6 features into ES5. It produces human-readable code, making it more welcoming when we don't have a firm grasp on all of the new features we're using.
-The online https://mjavascript.com/out/babel-repl[Babel REPL (Read-Evaluate-Print Loop)] is an excellent way of jumping right into learning ES6, without any of the hassle of installing Node.js and the `babel` CLI, and manually compiling source code.
+The online https://mjavascript.com/out/babel-repl[Babel REPL (Read-Evaluate-Print Loop)] is an excellent way of jumping right into learning ES6, without any of the hassle of installing Node.js and the `babel` CLI, and manually compiling source code.
The REPL provides us with a source code input area that gets automatically compiled in real time. We can see the compiled code to the right of our source code.
@@ -234,7 +234,7 @@ ESLint is a modern linter that packs several plugins, sporting different rules,
[source,shell]
----
-npm install eslint@3 --save-dev
+npm install eslint@4 --save-dev
----
Next, we need to configure ESLint. Since we installed `eslint` as a local dependency, we'll find its command-line tool in _node_modules/.bin_. Executing the following command will guide us through configuring ESLint for our project for the first time. To get started, indicate you want to use a popular style guide and choose Standard,footnoteref:[linters,Note that Standard is just a self-proclamation, and not actually standardized in any official capacity. It doesn't really matter which style guide you follow as long as you follow it consistently. Consistency helps reduce confusion while reading a project's codebase. The Airbnb style guide is also fairly popular and it doesn't omit semicolons by default, unlike Standard.] then pick JSON format for the configuration file:
@@ -311,7 +311,7 @@ When we run `lint-fix` we'll only get a pair of errors: `hello` is never used an
----
var goodbye = 'Goodbye!'
-function hello() {
+function hello () {
return goodbye
}
diff --git a/ch02.asciidoc b/ch02.asciidoc
index 8bec1f8..604de25 100644
--- a/ch02.asciidoc
+++ b/ch02.asciidoc
@@ -286,7 +286,7 @@ function puzzle() {
puzzle('a', 'b', 'c')(1, 2, 3)
----
-In this case, the `arguments` object refers to the context of the `puzzle` function, because arrow functions don't create a closure. For this reason, the printed arguments will be `'a', 'b', 'c'`.
+Because arrow functions don't have their own `arguments` keyword (or `this` or `super`), the lookup bubbles up to the outer scope of the `puzzle` function. That means the printed arguments will be `'a', 'b', 'c'`.
I've mentioned there are several flavors of arrow functions, but so far we've only looked at their fully fleshed version. What are the other ways to represent an ((("arrow functions", "lexical scoping", startref="af2ls")))((("lexical scoping", startref="ls2")))arrow function?
@@ -401,70 +401,69 @@ This ((("arrow functions", startref="af2")))((("arrow functions", "merits and us
==== Destructuring Objects
-Imagine ((("assignment destructuring", "objects", id="ad2o")))((("destructuring", "objects", id="d2o")))((("objects", "destructuring", id="o2d")))you had a program with some comic book characters, Bruce Wayne being one of them, and you want to refer to properties in the object that describes him. Here's the example object we'll be using for Batman:
+Imagine ((("assignment destructuring", "objects", id="ad2o")))((("destructuring", "objects", id="d2o")))((("objects", "destructuring", id="o2d")))you had a program describing a color palette and you want to refer to properties in the object that describes it. Here's an example object we'll be using for our palette:
[source,javascript]
----
-var character = {
- name: 'Bruce',
- pseudonym: 'Batman',
- metadata: {
- age: 34,
- gender: 'male'
+var palette = {
+ profile: 'intense-red',
+ name: 'Red',
+ color: {
+ code: `#f00`
},
- batarang: ['gas pellet', 'bat-mobile control', 'bat-cuffs']
+ luminosity: 0.8
}
----
-If you wanted a `pseudonym` variable referencing `character.pseudonym`, you could write the following bit of ES5 code. This is commonplace when, for instance, you'll be referencing `pseudonym` in several places in your codebase and you'd prefer to avoid typing out `character.pseudonym` each time:
+If you wanted a `profile` variable referencing `palette.profile`, you could write the following bit of ES5 code. This is commonplace when, for instance, you'll be referencing `profile` in several places in your codebase and you'd prefer to avoid typing out `palette.profile` each time:
[source,javascript]
----
-var pseudonym = character.pseudonym
+var profile = palette.profile
----
-With destructuring in assignment, the syntax becomes a bit more clear. As you can see in the next example, you don't have to write `pseudonym` twice, while still clearly conveying intent. The following statement is equivalent to the previous one written in ES5 code:
+With destructuring in assignment, the syntax becomes a bit more clear. As you can see in the next example, you don't have to write `profile` twice, while still clearly conveying intent. The following statement is equivalent to the previous one written in ES5 code:
[source,javascript]
----
-var { pseudonym } = character
+var { profile } = palette
----
Just like you could declare multiple comma-separated variables with a single `var` statement, you can also declare multiple variables within the curly braces of a destructuring expression:
[source,javascript]
----
-var { pseudonym, name } = character
+var { profile, name } = palette
----
In a similar fashion, you could mix and match destructuring with regular variable declarations in the same `var` statement. While this might look a bit confusing at first, it'll be up to any JavaScript coding style guides you follow to determine whether it's appropriate to declare several variables in a single statement. In any case, it goes to show the flexibility offered by destructuring syntax:
[source,javascript]
----
-var { pseudonym } = character, two = 2
+var { profile } = palette, two = 2
----
-If you want to extract a property named `pseudonym` but would like to declare it as a variable named `alias`, you can use the following destructuring syntax, known as _aliasing_. Note that you can use `alias` or any other valid variable name:
+If you want to extract a property named `profile` but would like to declare it as a variable named `id`, you can use the following destructuring syntax, known as _aliasing_. Note that you can use `id` or any other valid variable name:
[source,javascript]
----
-var { pseudonym: alias } = character
-console.log(alias)
-// <- 'Batman'
+var { profile: id } = palette
+console.log(id)
+// <- 'intense-red'
----
-While aliases don't look any simpler than the ES5 flavor, `alias = character.pseudonym`, ((("aliases", id="al2")))they start making sense when you consider the fact that destructuring supports deep structures, as in the following example:
+While aliases don't look any simpler than the ES5 flavor, `id = palette.profile`, ((("aliases", id="al2")))they start making sense when you consider the fact that destructuring supports deep structures, as in the following example:
[source,javascript]
----
-var { metadata: { gender } } = character
+var { color: { code } } = palette
----
In cases like the previous one, where you have deeply nested properties being destructured, you might be able to convey a property name more clearly if you choose an alias. Consider the next snippet, where a property named `code` wouldn't have been as indicative of its contents as `colorCode` could be:
[source,javascript]
----
-var { metadata: { gender: characterGender } } = character
+var { color: { code: colorCode } } = palette
----
The scenario we just saw repeats itself frequently, because properties are often named in the context of their host object. While `palette.color.code` is perfectly descriptive, `code` on its own could mean a wide variety of things, and aliases such as `colorCode` can help you bring context back into the variable name while still using destructuring.
@@ -473,9 +472,9 @@ Whenever you access a nonexistent property in ES5 notation, you get a value of `
[source,javascript]
----
-console.log(character.boots)
+console.log(palette.luminosity)
// <- undefined
-console.log(character['boots'])
+console.log(palette['luminosity'])
// <- undefined
----
@@ -483,8 +482,8 @@ With destructuring, the same behavior prevails. When declaring a destructured va
[source,javascript]
----
-var { boots } = character
-console.log(boots)
+var { luminosity } = palette
+console.log(luminosity)
// <- undefined
----
@@ -492,7 +491,7 @@ A destructured declaration accessing a nested property of a parent object that's
[source,javascript]
----
-var { boots: { size } } = character
+var { stroke: { width } } = palette
// <- Exception
var { missing } = null
// <- Exception
@@ -511,37 +510,37 @@ As part of destructuring, you can provide default values for those cases where t
[source,javascript]
----
-var { boots = { size: 10 } } = character
-console.log(boots)
-// <- { size: 10 }
+var { description = 'This is a color palette' } = palette
+console.log(description)
+// <- 'This is a color palette'
----
Default values can also be provided in nested property destructuring.
[source,javascript]
----
-var { metadata: { enemy = 'Satan' } } = character
-console.log(enemy)
-// <- 'Satan'
+var { color: { density = 320 } } = palette
+console.log(density)
+// <- 320
----
For use in combination with aliases, you should place the alias first, and then the default value, as shown next.
[source,javascript]
----
-var { boots: footwear = { size: 10 } } = character
+var { color: paletteColor = { density: 320 } } = palette
----
-It's possible to use the ((("computed property names")))computed property names syntax in destructuring patterns. In this case, however, you're required to provide an alias to be used as the variable name. That's because computed property names allow arbitrary expressions and thus the compiler wouldn't be able to infer a variable name. In the following example we use the `value` alias, and a computed property name to extract the `boots` property from the `character` object.
+It's possible to use the ((("computed property names")))computed property names syntax in destructuring patterns. In this case, however, you're required to provide an alias to be used as the variable name. That's because computed property names allow arbitrary expressions and thus the compiler wouldn't be able to infer a variable name. In the following example we use the `paletteProfile` alias, and a computed property name to extract the `profile` property from the `palette` object.
[source,javascript]
----
-var { ['boo' + 'ts']: characterBoots } = character
-console.log(characterBoots)
+var { ['pro' + 'file']: paletteProfile } = palette
+console.log(paletteProfile)
// <- true
----
-This flavor of destructuring is probably the least useful, as `characterBoots = character[type]` is usually simpler than `{ [type]: characterBoots } = character`, as it's a more sequential statement. That being said, the feature is useful when you have properties you want to declare in the object literal, as opposed to using subsequent assignment statements.
+This flavor of destructuring is probably the least useful, as `sourceProperty = source[property]` is usually simpler than `{ [property]: sourceProperty } = source`, as it's a more sequential statement. That being said, the feature is useful when you have properties you want to declare in the object literal, as opposed to using subsequent assignment statements.
That's it, as far as objects go, in terms of destructuring. ((("assignment destructuring", "objects", startref="ad2o")))((("destructuring", "objects", startref="d2o")))((("objects", "destructuring", startref="o2d")))((("aliases", startref="al2")))What about arrays?
@@ -746,7 +745,7 @@ console.log(random({ max: 24 }))
// <- 18
----
-Regular ((("assignment destructuring", "function parameters", startref="ad2fpd")))((("destructuring", "function parameters", startref="d2fpd")))((("function parameters", startref="fpd2")))expressions are another great fit for destructuring. Destructuring empowers you to name groups from a match without having to resort to index numbers. Here's an example `RegExp` that could be used for parsing simple dates, and an example of destructuring those dates into each of their components. The first entry in the resulting array is reserved for the raw input string, and we can discard it.
+Regular ((("assignment destructuring", "function parameters", startref="ad2fpd")))((("destructuring", "function parameters", startref="d2fpd")))((("function parameters", startref="fpd2")))expressions are another great fit for destructuring. Destructuring empowers you to name groups from a match without having to resort to index numbers. Here's an example `RegExp` that could be used for parsing simple dates, and an example of destructuring those dates into each of their components. The first entry in the resulting array is reserved for the full matched text, and we can discard it.
[source,javascript]
----
@@ -1034,8 +1033,8 @@ A second line\n\
Then a third line'
var concatenated =
-'The first line\n' `
-'A second line\n' `
+'The first line\n' +
+'A second line\n' +
'Then a third line'
var joined = [
@@ -1186,7 +1185,7 @@ var name = 'Maurice'
var emotion = 'thrilled'
var text = tag`Hello, ${ name }. I am ${ emotion } to meet you!`
console.log(text)
-// <- 'Hello Maurice, I am thrilled to meet you!'
+// <- 'Hello, Maurice. I am thrilled to meet you!'
----
Multiple use cases apply to tagged templates. One possible use case might be to make user input uppercase, making the string sound satirical. That's what the following piece of code does. We've modified `tag` slightly so that any interpolated strings are uppercased.
@@ -1201,7 +1200,7 @@ function upper(parts, ...values) {
var name = 'Maurice'
var emotion = 'thrilled'
upper`Hello, ${ name }. I am ${ emotion } to meet you!`
-// <- 'Hello MAURICE, I am THRILLED to meet you!'
+// <- 'Hello, MAURICE. I am THRILLED to meet you!'
----
A decidedly more useful use case would be to sanitize expressions interpolated into your templates, automatically, using a tagged template. Given a template where all expressions are considered user input, we could use a hypothetical `sanitize` library to remove HTML tags and similar hazards, preventing cross-site scripting (XSS) attacks where users might inject malicious HTML into our websites.
diff --git a/ch03.asciidoc b/ch03.asciidoc
index ca29f8f..ea97fea 100644
--- a/ch03.asciidoc
+++ b/ch03.asciidoc
@@ -337,7 +337,7 @@ class Plum extends createJuicyFruit('plum', 30) {
}
----
-Let's move ((("prototypal inheritance", startref="pi3)))onto `Symbol`. While not an iteration or flow control mechanism, learning about `Symbol` is crucial to shaping an understanding of iteration protocols, which are discussed at length later in ((("classes", startref="class3")))((("classes", "extending", startref="class3ext")))the chapter.
+Let's move ((("prototypal inheritance", startref="pi3)))onto `Symbol`. While not an iteration or flow control mechanism, learning about `Symbol` is crucial to shaping an understanding of iteration protocols, which are discussed at length in ((("classes", startref="class3")))((("classes", "extending", startref="class3ext")))the next chapter.
=== Symbols
@@ -428,7 +428,7 @@ console.log(JSON.stringify(character))
// <- '{"name":"Penguin"}'
----
-That being said, symbols are by no means a safe mechanism to conceal properties. Even though you won't stumble upon symbol properties when using reflection or serialization methods, symbols are revealed by a dedicated method as shown in the next snippet of code. In other words, symbols are not nonenumerable, but hidden in plain sight. Using `Object.getOwnPropertySymbols` we can retrieve all symbols used as property keys on any given object.
+That being said, symbols are by no means a safe mechanism to conceal properties. Even though you won't stumble upon symbol properties when using pre-ES6 reflection, iteration or serialization methods, symbols are revealed by a dedicated method as shown in the next snippet of code. In other words, symbols are not nonenumerable, but hidden in plain sight. Using `Object.getOwnPropertySymbols` we can retrieve all symbols used as property keys on any given object.
[source,javascript]
----
@@ -755,7 +755,7 @@ console.log(Object.assign({}, defaults, options))
Note, however, that `Object.assign` doesn't cater to every need. While most user-land implementations have the ability to perform deep assignment, `Object.assign` doesn't offer a recursive treatment of objects. Object values are assigned as properties on `target` directly, instead of being recursively assigned key by key.
-In the following bit of code you might expect the `f` property to be added to `target.a` while keeping `b.c` and `b.d` intact, but the `b.c` and `b.d` properties are lost when using `Object.assign`.
+In the following bit of code you might expect the `f` property to be added to `target.a` while keeping `a.b` and `a.d` intact, but the `a.b` and `a.d` properties are lost when using `Object.assign`.
[source,javascript]
----
@@ -771,7 +771,7 @@ Object.assign({}, { a: ['b', 'c', 'd'] }, { a: ['e', 'f'] })
// <- { a: ['e', 'f'] }
----
-At the time of this writing, there's an ECMAScript stage 3 proposalpass:[You can find the proposal draft at GitHub.] to implement spread in objects, similar to how you can spread iterable objects onto an array in ES6. Spreading an ((("objects", "object spread")))object onto another is equivalent to using an `Object.assign` function call.
+At the time of this writing, there's an ECMAScript stage 3 proposalpass:[You can find the proposal draft at GitHub.] to implement spread in objects, similar to how you can spread iterable objects onto an array in ES6. Spreading an ((("objects", "object spread")))object onto another is equivalent to using an `Object.assign` function call.
The following piece of code shows a few cases where we're spreading the properties of an object onto another one, and their `Object.assign` counterpart. As you can see, using object spread is more succinct and should be preferred where possible.
@@ -877,14 +877,14 @@ Using `Object.setPrototypeOf` to change the prototype of an object is an expensi
[quote, Mozilla Developer Network]
____
-Changing the prototype of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in a `obj.__proto__ = …` statement, but may extend to any code that has access to any object whose prototype has been altered. If you care about performance you should avoid setting the prototype of an object. Instead, create a new ((("objects", "built-in improvements", startref="ob3bii")))object with the desired ((("objects", "setting prototypes", startref="ob3sp")))((("Object.setPrototypeOf", startref="ospo3")))prototype using `Object.create()`.
+Changing the prototype of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in a `Object.setPrototypeOf(…)` statement, but may extend to any code that has access to any object whose prototype has been altered. If you care about performance you should avoid setting the prototype of an object. Instead, create a new ((("objects", "built-in improvements", startref="ob3bii")))object with the desired ((("objects", "setting prototypes", startref="ob3sp")))((("Object.setPrototypeOf", startref="ospo3")))prototype using `Object.create()`.
____
****
=== Decorators
-Decorators are, ((("Decorators", id="dec3")))as most things programming, definitely not a new concept. The pattern is fairly commonplace in modern programming languages: you have _attributes_ in C#, they're called _annotations_ in Java, there are _decorators_ in Python, and the list goes on. There's a JavaScript decorators proposalpass:[You can find the proposal draft online at GitHub.] in the works. It is currently sitting at stage 2 of the TC39 process.
+Decorators are, ((("Decorators", id="dec3")))as most things programming, definitely not a new concept. The pattern is fairly commonplace in modern programming languages: you have _attributes_ in C#, they're called _annotations_ in Java, there are _decorators_ in Python, and the list goes on. There's a JavaScript decorators proposalpass:[ in the works and you can find the draft online at GitHub.] It is currently sitting at stage 2 of the TC39 process.
==== A Primer on JavaScript Decorators
@@ -1043,7 +1043,7 @@ function getCommandProperties(ctor) {
return [...properties]
}
getCommandProperties(Dog)
-// <- [{ key: 'name', readLevel: 'game-master',
+// <- [{ key: 'name', readLevel: 'game-master',
// writeLevel: 'game-master' }]
----
diff --git a/ch04.asciidoc b/ch04.asciidoc
index 2bf7279..e2cbf59 100644
--- a/ch04.asciidoc
+++ b/ch04.asciidoc
@@ -1169,7 +1169,7 @@ console.log([...salute('you')])
// <- ['h', 'e', 'l', 'l', 'o', ' ', 'y', 'o', 'u']
----
-To reiterate, you can `yield*` anything that adheres to the iterable protocol, not merely strings. That includes generator objects, arrays, `arguments`, `NodeList` in the browser, and just about anything, provided it implements `System.iterator`. The following example demonstrates how you could mix `yield` and `yield*` statements to describe a sequence of values using generator functions, an iterable object, and the spread operator. Can you deduce what the `console.log` statement would print?
+To reiterate, you can `yield*` anything that adheres to the iterable protocol, not merely strings. That includes generator objects, arrays, `arguments`, `NodeList` in the browser, and just about anything, provided it implements `Symbol.iterator`. The following example demonstrates how you could mix `yield` and `yield*` statements to describe a sequence of values using generator functions, an iterable object, and the spread operator. Can you deduce what the `console.log` statement would print?
[source,javascript]
----
@@ -1376,7 +1376,7 @@ class Node {
}
----
-Trees can be traversed using depth-first search, where we always try to go deeper into the tree structure, and when we can't we move to the next children on the list. In the following tree structure, a depth-first search algorithm would traverse the tree visiting the nodes following the `1, 2, 3, 4, 5, 6, 7, 8, 9, 10` order.
+Trees can be traversed using depth-first search, where we always try to go deeper into the tree structure, and when we can't move to the next children on the list. In the following tree structure, a depth-first search algorithm would traverse the tree visiting the nodes following the `1, 2, 3, 4, 5, 6, 7, 8, 9, 10` order.
[source,javascript]
----
diff --git a/ch06.asciidoc b/ch06.asciidoc
index 93f1603..f77ba57 100644
--- a/ch06.asciidoc
+++ b/ch06.asciidoc
@@ -205,7 +205,7 @@ const validations = new Map()
const validator = {
set(target, key, value) {
if (validations.has(key)) {
- return validations[key](value)
+ validations.get(key)(value)
}
return Reflect.set(target, key, value)
}
diff --git a/ch08.asciidoc b/ch08.asciidoc
index b0fc93f..28aa5cc 100644
--- a/ch08.asciidoc
+++ b/ch08.asciidoc
@@ -520,7 +520,7 @@ console.log(counter.default) // <- 2
==== Dynamic import()
-At the ((("dynamic import()", id="di8")))((("ES6 modules", "dynamic import()", id="esm8di")))time of this writing, a proposal for dynamic ++import()++pass:[] expressions is sitting at stage 3 of the TC39 proposal review process. Unlike `import` statements, which are statically analyzed and linked, `import()` loads modules at runtime, returning a promise for the module namespace object after fetching, parsing, and executing the requested module and all of its dependencies.
+At the ((("dynamic import()", id="di8")))((("ES6 modules", "dynamic import()", id="esm8di")))time of this writing, a proposal for dynamic ++import()++pass:[Check out the proposal specification draft.] expressions is sitting at stage 3 of the TC39 proposal review process. Unlike `import` statements, which are statically analyzed and linked, `import()` loads modules at runtime, returning a promise for the module namespace object after fetching, parsing, and executing the requested module and all of its dependencies.
The module specifier can be any string, like with `import` statements. Keep in mind `import` statements only allow statically defined plain string literals as module specifiers. In contrast, we're able to use template literals or any valid JavaScript expression to produce the module specifier string for `import()` function calls.
diff --git a/ch09.asciidoc b/ch09.asciidoc
index 8b77039..bfdd181 100644
--- a/ch09.asciidoc
+++ b/ch09.asciidoc
@@ -802,7 +802,7 @@ const pistol = {
caliber: 50,
trigger() {
setTimeout(() => {
- console.log(`Fired caliber ${ self.caliber } pistol`)
+ console.log(`Fired caliber ${ this.caliber } pistol`)
}, 1000)
}
}
diff --git a/preface.asciidoc b/preface.asciidoc
index d713ca4..2719848 100644
--- a/preface.asciidoc
+++ b/preface.asciidoc
@@ -11,7 +11,7 @@ This book is meant for web developers, enthusiasts, and professionals with a wor
The goal of this book is to provide an approachable way of learning the latest developments in JavaScript: ES6 and later. ES6 was a huge update to the language, and it came out around the same time as a streamlined specification development process. Around this time I wrote quite a few blog posts about the different features in ES6, which became a bit popular. There are quite a few other books on ES6 out there, but they're a little different from what I had in mind for a book on ES6 and beyond. This book tries to explain features in detail without getting caught up in the specification, its implementation details, or unlikely corner cases that would almost certainly need to be researched online if happened upon.
-Instead of extreme thoroughness, the book places its utmost focus in the learning process, having sorted its material in such an incremental way that you don't have to scan ahead in the book for the definition of something else. Armed with practical examples, _Practical Modern JavaScript_ goes beyond ES6 to capture the changes to the language since June 2015--when the ES6 specification was finalized--including async functions, object destructuring, dynamic imports, `Promise#finally`, and async generators.
+Instead of extreme thoroughness, the book places its utmost focus in the learning process, having sorted its material in such an incremental way that you don't have to scan ahead in the book for the definition of something else. Armed with practical examples, _Practical Modern JavaScript_ goes beyond ES6 to capture the changes to the language since June 2015--when the ES6 specification was finalized--including async functions, object rest/spread properties, dynamic imports, `Promise#finally`, and async generators.
Lastly, this book has the goal of establishing a baseline we can take for granted in the rest of the Modular JavaScript series. After having learned the latest language features in this first book, we'll be all set to discuss modular design, testing, and deployment, without having to diverge into language features whenever they're used in a code example. This incremental and modular approach is meant to be pervasive across the series, each book, each chapter, and each section.
@@ -65,7 +65,7 @@ pass:[http://oreilly.com/safari].
+For more information, please visit pass:[http://oreilly.com/safari].
[role="pagebreak-before"]
=== How to Contact Us
@@ -101,7 +101,7 @@ Watch us on YouTube: link:$$http://www.youtube.com/oreillymedia$$[]
Like virtually every human task ever carried out, _Practical Modern JavaScript_ was made possible only by building upon the work of others. I want to thank Nan Barber, my editor at O'Reilly, for her fantastic support along the ride of writing this book. Ally MacDonald, another editor at O'Reilly, helped me out in the early days of the project and is the foremost reason why Modular JavaScript became a book series, as she helped me conjure up a modular approach to teaching JavaScript.
-This book had a phenomenal ensemble of technical reviewers. Many of these folks are on TC39, the technical committee devoted to pushing JavaScript forward, and it's deeply humbling that they gave up some of their time to help future-proof this book. As always, Mathias Bynens (TC39, Google) proved instrumental to proofing everything in the book with regards to Unicode standards and held my work to a high degree of consistency in terms of code snippets. Kent C. Dodds (TC39, PayPal) ingeniously offered video reviews where he identified weak spots and helped improve the book. Jordan Harband (TC39, Airbnb) came through with deep technical commentary about many of the JavaScript features discussed in the book, and along with Alex Russell (TC39, Google) helped me iron out the history of JavaScript and its standards body for the first chapter. Ingvar Stepanyan (Cloudflare) was also a sharp eye in identifying code issues and pinpointed mistakes around low-level aspects of the specification. Brian Terlson (TC39 editor, Microsoft) also helped out with timelines and details around TC39. Rod Vagg (Node.js) provided insight that lead to better code examples and more consistent code style throughout the book.
+This book had a phenomenal ensemble of technical reviewers. Many of these folks are on TC39, the technical committee devoted to pushing JavaScript forward, and it's deeply humbling that they gave up some of their time to help future-proof this book. As always, Mathias Bynens (TC39, Google) proved instrumental to proofing everything in the book with regards to Unicode standards and held my work to a high degree of consistency in terms of code snippets. Kent C. Dodds (TC39, PayPal) ingeniously offered video reviews where he identified weak spots and helped improve the book. Jordan Harband (TC39, Airbnb) came through with deep technical commentary about many of the JavaScript features discussed in the book, and along with Alex Russell (TC39, Google) helped me iron out the history of JavaScript and its standards body for the first chapter. Ingvar Stepanyan (Cloudflare) was also a sharp eye in identifying code issues and pinpointed mistakes around low-level aspects of the specification. Brian Terlson (TC39 editor, Microsoft) also helped out with timelines and details around TC39. Rod Vagg (Node.js) provided insight that led to better code examples and more consistent code style throughout the book.
Brendan Eich (TC39, Brave CEO) provided a trove of insight into the early days of JavaScript and TC39, which proved essential to the development of the first chapter. And naturally, if not for him, you wouldn't be holding this book in your hands.