diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc index 5472201..b675847 100644 --- a/chapters/ch01.asciidoc +++ b/chapters/ch01.asciidoc @@ -45,7 +45,7 @@ The sixth edition is a significant milestone in the history of JavaScript. Besid Having spent ten years without observing significant change to the language specification after ES3, and four years for ES6 to materialize, it was clear the TC39 process needed to improve. The revision process used to be deadline-driven. Any delay in arriving at consensus would cause long wait periods between revisions, which lead to feature creep, causing more delays. Minor revisions were delayed by large additions to the specification, and large additions faced pressure to finalize so that the revision would be pushed through avoiding further delays. -Since ES6 came out, TC39 has streamlinedfootnote:[You can find the September 2013 presentation which lead to the streamlined proposal revisioning process here: https://mjavascript.com/out/tc39-improvement.] its proposal revisioning process and adjusted it to meet modern expectations: the need to iterate more often and consistently, and to democratize specification development. At this point, TC39 moved from an ancient Word-based flow to using ecmarkup and GitHub Pull Requests, greatly increasing the number of proposalsfootnoteref:[proposals,You can find all proposals being considered by TC39 at https://mjavascript.com/out/tc39-proposals.] being created as well as external participation by non-members. +Since ES6 came out, TC39 has streamlinedfootnote:[You can find the September 2013 presentation which lead to the streamlined proposal revisioning process here: https://mjavascript.com/out/tc39-improvement.] its proposal revisioning process and adjusted it to meet modern expectations: the need to iterate more often and consistently, and to democratize specification development. At this point, TC39 moved from an ancient Word-based flow to using ecmarkup (an HTML superset used to format ECMAScript specifications) and GitHub Pull Requests, greatly increasing the number of proposalsfootnoteref:[proposals,You can find all proposals being considered by TC39 at https://mjavascript.com/out/tc39-proposals.] being created as well as external participation by non-members. Firefox, Chrome, Edge, Safari and Node.js all offer over 95% compliance of the ES6 specification,footnote:[For a detailed ES6 compatibility report across browsers, check out the following table: https://mjavascript.com/out/es6-compat.] but we’ve been able to use the features as they came out in each of these browsers rather than having to wait until the flip of a switch when their implementation of ES6 was 100% finalized. @@ -73,7 +73,7 @@ Babel and similar compilers that take code as input and produce output native to This transformation can be done at build-time, so that consumers receive code that's well supported by their JavaScript runtime of choice. This mechanism improves the runtime support baseline, giving JavaScript developers the ability to take advantage of new language features and syntax sooner. It is also significantly beneficial to specification writers and implementors, as it allows them to collect feedback regarding viability, desirability, and possible bugs or corner cases. -A transpiler can take the ES6 source code we write and produce ES5 code that browsers can interpret more consistently. This is the most reliable way of running ES6 code in production today: using a build step to produce ES5 code that any modern browser can execute. +A transpiler can take the ES6 source code we write and produce ES5 code that browsers can interpret more consistently. This is the most reliable way of running ES6 code in production today: using a build step to produce ES5 code that most old browsers, as well as modern browsers, can execute. The same applies to ES7 and beyond. As new versions of the language specification are released every year, we can expect compilers to support ES2017 input, ES2018 input and beyond. Similarly, as browser support becomes better, we can also expect compilers to reduce complexity in favor of ES6 output, then ES7 output, and so on. In this sense, we can think of JavaScript-to-JavaScript transpilers as a moving window that takes code written using the latest available language semantics and produces the most modern code they can output without compromising browser support. @@ -115,7 +115,7 @@ Besides the REPL, Babel offers a command-line tool written as a Node.js package. You can download Node.js from their website: https://mjavascript.com/out/node. After installing Node, you'll be able to use the +npm+ command-line tool in your terminal. ==== -Before getting started we'll create a project directory and a +package.json+ file, which is a manifest used to describe Node.js applications. We'll create a +package.json+ file through the +npm+ CLI as well. +Before getting started we'll make a project directory and a +package.json+ file, which is a manifest used to describe Node.js applications. We can create the +package.json+ file through the +npm+ CLI. [source,shell] ---- @@ -183,7 +183,7 @@ Together with the packages we've installed in the previous step, a minimal +pack [NOTE] ==== -Any commands enumerated in the +scripts+ object can be executed through +npm run +, which modifies the +$PATH+ environment variable so that we can run the command-line executables found in +babel-cli+ without installing +babel-cli+ globally on our system. +Any commands enumerated in the +scripts+ object can be executed through +npm run +, which temporarily modifies the +$PATH+ environment variable so that we can run the command-line executables found in +babel-cli+ without installing +babel-cli+ globally on our system. ==== If you execute +npm run build+ in your terminal now, you'll note that a +dist/example.js+ file is created. The output file will be identical to our original file, because Babel doesn't make assumptions, and we have to configure it first. Create a +.babelrc+ file next to +package.json+, and write the following JSON in it. diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc index 834bea0..336075c 100644 --- a/chapters/ch02.asciidoc +++ b/chapters/ch02.asciidoc @@ -394,8 +394,6 @@ Arrow functions are neat when it comes to defining anonymous functions that shou // <- 8 ---- -The next feature we'll analyze is destructuring in assignment. Let's see what that's all about. - === 2.3 Assignment Destructuring This is one of the most flexible and expressive features in ES6. It's also one of the simplest. It binds properties to as many variables as you need. It works with objects, arrays, and even in +function+ parameter lists. Let's go step by step, starting with objects. @@ -442,7 +440,7 @@ In a similar fashion, you could mix and match destructuring with regular variabl [source,javascript] ---- -var { pseudonym, name } = character, two = 2 +var { pseudonym } = character, 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. @@ -464,13 +462,7 @@ var { metadata: { gender } } = character 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 palette = { - color: { - name: 'Red', - code: '#f00' - } -} -var { color: { code: colorCode } } = palette +var { metadata: { gender: characterGender } } = character ---- 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. @@ -498,7 +490,7 @@ A destructured declaration accessing a nested property of a parent object that's [source,javascript] ---- -var { batmobile: { gear } } = character +var { boots: { size } } = character // <- Exception var { missing } = null // <- Exception @@ -517,9 +509,9 @@ As part of destructuring, you can provide default values for those cases where t [source,javascript] ---- -var { boots = true } = character +var { boots = { size: 10 } } = character console.log(boots) -// <- true +// <- { size: 10 } ---- Default values can also be provided in nested property destructuring. @@ -535,20 +527,19 @@ For use in combination with aliases, you should place the alias first, and then [source,javascript] ---- -var { boots: footwear = true } = character +var { boots: footwear = { size: 10 } } = character ---- -It's possible to use the 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 isn't always able to infer a variable name. In the following example we use the +value+ alias, and a computed property name to extract the +scientist+ property from the +person+ object. +It's possible to use the 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. [source,javascript] ---- -var person = { scientist: true } -var { ['scient' + 'ist']: value } = person -console.log(value) +var { ['boo' + 'ts']: characterBoots } = character +console.log(characterBoots) // <- true ---- -This flavor of destructuring is probably the least useful, as +value = person[type]+ is easier to read than +{ [type]: value } = person+, as it's a more sequential statement. That being said, the feature could still be useful in some deep destructuring scenarios. +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. That's it, as far as objects go, in terms of destructuring. What about arrays? @@ -760,6 +751,17 @@ function splitDate (date) { var [, year, month, day] = splitDate('2015-11-06') ---- +You'll want to be careful when the regular expression doesn't match, as that returns `null`. Perhaps a better approach would be to test for the failure case before destructuring, as shown in the following bit of code. + +[source,javascript] +---- +var matches = splitDate('2015-11-06') +if (matches === null) { + return +} +var [, year, month, day] = matches +---- + Let's turn our attention to spread and rest operators next. === 2.4 Rest Parameters and Spread Operator @@ -1069,7 +1071,7 @@ var html = `
` ---- -The template we've just prepared would produce output like what's shown in the following snippet of code. Note how spacing was preserved, and how +
  • + tags are properly indented thanks for how we joined them together using a few spaces. +The template we've just prepared would produce output like what's shown in the following snippet of code. Note how spacing was preservedfootnote:[When using multi-line template literals, spacing isn't preserved automatically. However, in many cases we can provide just enough indentation to make it work. Be wary of indented code blocks which may result in undesired indentation due to our code block being nested.], and how +
  • + tags are properly indented thanks for how we joined them together using a few spaces. [source,html] ---- @@ -1182,7 +1184,7 @@ console.log(text) // <- '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. +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. [source,javascript] ---- @@ -1197,7 +1199,7 @@ console.log(html) // <- '
    A malicious comment
    ' ---- -Phew, that malicious +