Skip to content

Commit e884f0d

Browse files
authored
Follow review by @rvagg (#28)
* Start review of @rvagg's commentary! 🎉 * naming clarification and arguments example. * @rvagg's comments for chapter 2 addressed. should check `for` examples for correctness. * review chapters 3 and 4 via @rvagg * finish applying @rvagg's review
1 parent 93ba1ac commit e884f0d

11 files changed

+385
-171
lines changed

chapters/ch01.asciidoc

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[ecmascript-and-the-future-of-javascript]]
22
== ECMAScript and the Future of JavaScript
33

4-
JavaScript has gone from being a 1995 marketing ploy to gain a tactical advantage, to becoming the core programming experience in the world's most widely used application runtime platform in 2017. The language doesn't merely run in browsers anymore, but is also used to create desktop and mobile applications, in hardware devices, and even in the vacuum of space.
4+
JavaScript has gone from being a 1995 marketing ploy to gain a tactical advantage, to becoming the core programming experience in the world's most widely used application runtime platform in 2017. The language doesn't merely run in browsers anymore, but is also used to create desktop and mobile applications, in hardware devices, and even in space suit design at NASA.
55

66
How did JavaScript get here, and where is it going next?
77

@@ -47,7 +47,7 @@ Having spent ten years without observing significant change to the language spec
4747

4848
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.
4949

50-
Firefox, Chrome, Edge, Safari and Node.js all offer over 95% compliancy 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.
50+
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.
5151

5252
The new process involves four different maturity stagesfootnote:[The TC39 proposal process documentation can be found at https://mjavascript.com/out/tc39-process.]. The more mature a proposal is, the more likely it is to eventually make it into the specification.
5353

@@ -160,7 +160,9 @@ For the next step, we'll replace the value of the +scripts+ property in +package
160160
[source,json]
161161
----
162162
{
163-
"build": "babel src --out-dir dist"
163+
"scripts": {
164+
"build": "babel src --out-dir dist"
165+
}
164166
}
165167
----
166168

@@ -258,12 +260,16 @@ Referencing the +node_modules/.bin+ directory, an implementation detail of how n
258260

259261
[source,json]
260262
----
261-
"lint": "eslint ."
263+
{
264+
"scripts": {
265+
"lint": "eslint ."
266+
}
267+
}
262268
----
263269

264270
As you might recall from the Babel example, +npm+ add +node_modules+ to the +PATH+ when executing scripts. To lint our codebase, we can execute +npm run lint+ and npm will find the ESLint CLI embedded deep in the +node_modules+ directory.
265271

266-
Let's consider the following +example.js+ file, which is purposely ridden with style issues, to demonstrate what ESLint does.
272+
Let's consider the following +example.js+ file, which is purposely riddled with style issues, to demonstrate what ESLint does.
267273

268274
[source,javascript]
269275
----
@@ -283,7 +289,11 @@ ESLint is able to fix most style problems automatically if we pass in a +--fix+
283289

284290
[source,json]
285291
----
286-
"lint-fix": "eslint . --fix"
292+
{
293+
"scripts": {
294+
"lint-fix": "eslint . --fix"
295+
}
296+
}
287297
----
288298

289299
When we run +lint-fix+ we'll only get a pair of errors: +hello+ is never used and +false+ is a constant condition. Every other error has been fixed in place, resulting in the bit of source code found below. The remaining errors weren't fixed because ESLint avoids making assumptions about our code, and prefers not to incur in semantic changes. In doing so, +--fix+ becomes a useful tool to resolve code style wrinkles without risking a broken program as a result.
@@ -317,7 +327,7 @@ We get several new mechanics to describe asynchronous code flows in ES6: promise
317327

318328
There's a common practice in JavaScript where developers use plain objects to create hash maps with arbitrary string keys. This can lead to vulnerabilities if we're not careful and let user input end up defining those keys. ES6 introduces a few different native built-ins to manage sets and maps, which don't have the limitation of using string keys exclusively. These collections are explored in chapter 5.
319329

320-
Proxy objects redefine what can be done through JavaScript reflection. Proxy objects are similar to proxies in other contexts, such as web traffic routing. They can intercept any interaction with a JavaScript object such as defining, deleting, or accessing a property. Given the mechanics of how proxies work, they are impossible to implement holistically as a polyfill. We'll devote chapter 6 to understanding proxies.
330+
Proxy objects redefine what can be done through JavaScript reflection. Proxy objects are similar to proxies in other contexts, such as web traffic routing. They can intercept any interaction with a JavaScript object such as defining, deleting, or accessing a property. Given the mechanics of how proxies work, they are impossible to polyfill holistically: polyfills exist, but they have limitations making them incompatible with the specification in some use cases. We'll devote chapter 6 to understanding proxies.
321331

322332
Besides new built-ins, ES6 comes with several updates to +Number+, +Math+, +Array+, and strings. In chapter 7 we'll go over a plethora of new instance and static methods added to these built-ins.
323333

chapters/ch02.asciidoc

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ var example = (parameters) => {
232232
}
233233
----
234234

235-
While arrow functions look very similar to your typical anonymous function, they are fundamentally different: arrow functions can't have a name, they can't be used as constructors, they don't have a +prototype+ property, and they are bound to their lexical scope.
235+
While arrow functions look very similar to your typical anonymous function, they are fundamentally different: arrow functions can't be named explicitly, although modern runtimes can infer a name based on the variable they're assigned to; they can't be used as constructors nor do they have a +prototype+ property, meaning you can't use +new+ on an arrow function; and they are bound to their lexical scope, which is the reason why they don't alter the meaning of +this+.
236236

237237
Let's dig into their semantic differences with traditional functions, the many ways to declare an arrow function, and practical use cases.
238238

@@ -261,6 +261,32 @@ If we had defined the function passed to +setInterval+ as a regular anonymous fu
261261

262262
In a similar fashion, lexical binding in ES6 arrow functions also means that function calls won't be able to change the +this+ context when using +.call+, +.apply+, +.bind+, etc. That limitation is usually more useful than not, as it ensures that the context will always be preserved and constant.
263263

264+
Let's now shift our attention to the following example. What do you think the `console.log` statement will print?
265+
266+
[source,javascript]
267+
----
268+
function puzzle () {
269+
return function () {
270+
console.log(arguments)
271+
}
272+
}
273+
puzzle('a', 'b', 'c')(1, 2, 3)
274+
----
275+
276+
The answer is that `arguments` refers to the context of the anonymous function, and thus the arguments passed to that function will be printed. In this case, those arguments are `1, 2, 3`.
277+
278+
What about in the following case, where we use an arrow function instead of the anonymous function in the previous example?
279+
280+
[source,javascript]
281+
----
282+
function puzzle () {
283+
return () => console.log(arguments)
284+
}
285+
puzzle('a', 'b', 'c')(1, 2, 3)
286+
----
287+
288+
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'`.
289+
264290
I've mentioned there's several flavors of arrow functions, but so far we've only looked at their fully fleshed version. What are the others way to represent an arrow function?
265291

266292
==== 2.2.2 Arrow Function Flavors
@@ -274,7 +300,7 @@ var example = (parameters) => {
274300
}
275301
----
276302

277-
An arrow function with exactly one parameter can omit the parenthesis. This is optional. It's useful when passing the arrow function to another method, as it reduces the amount of parenthesis involved, making it easier for humans to parse the code.
303+
An arrow function with exactly one parameter can omit the parenthesis. This is optional. It's useful when passing the arrow function to another method, as it reduces the amount of parenthesis involved, making it easier for some humans to parse the code.
278304

279305
[source,javascript]
280306
----
@@ -738,7 +764,7 @@ Let's turn our attention to spread and rest operators next.
738764

739765
=== 2.4 Rest Parameters and Spread Operator
740766

741-
Before ES6, interacting with an arbitrary amount of function parameters was complicated. You had to use +arguments+, which isn't an array but has a +length+ property. Usually you'd end up casting the +arguments+ object into an actual array using +Array.prototype.slice.call+, and going from there, as shown in the following snippet.
767+
Before ES6, interacting with an arbitrary amount of function parameters was complicated. You had to use +arguments+, which isn't an array but has a +length+ property. Usually you'd end up casting the +arguments+ object into an actual array using +Array#slice.call+, and going from there, as shown in the following snippet.
742768

743769
[source,javascript]
744770
----
@@ -861,8 +887,8 @@ In ES6, you can combine spread with array destructuring. The following piece of
861887
862888
[source,javascript]
863889
----
864-
var [first, second, ...rest] = ['a', 'b', 'c', 'd', 'e']
865-
console.log(rest)
890+
var [first, second, ...other] = ['a', 'b', 'c', 'd', 'e']
891+
console.log(other)
866892
// <- ['c', 'd', 'e']
867893
----
868894
@@ -921,8 +947,8 @@ The following table summarizes the use cases we've discussed for the spread oper
921947
|=======
922948
|Use Case|ES5|ES6
923949
|Concatenation|+[1, 2].concat(more)+|+[1, 2, ...more]+
924-
|Push onto list|+list.push.apply(list, [3, 4])+|+list.push(...[3, 4])+
925-
|Destructuring|+a = list[0], rest = list.slice(1)+ | +[a, ...rest] = list+
950+
|Push an array onto list|+list.push.apply(list, items)+|+list.push(...items)+
951+
|Destructuring|+a = list[0], other = list.slice(1)+ | +[a, ...other] = list+
926952
|+new+ and +apply+|+new (Date.bind.apply(Date, [null,2015,31,8]))+| +new Date(...[2015,31,8])+
927953
|=======
928954

@@ -1062,7 +1088,37 @@ The template we've just prepared would produce output like what's shown in the f
10621088
</article>
10631089
----
10641090

1065-
Sometimes, it might be a good idea to pre-process the results of expressions before inserting them into your templates. For these advanced kinds of use cases, it's possible to use another feature of template literals called tagged templates.
1091+
A downside when it comes to multi-line template literals is indentation. The following example shows a typically indented piece of code with a template literal contained in a function. While we may have expected no indentation, the string is has four spaces of indentation.
1092+
1093+
[source,javascript]
1094+
----
1095+
function getParagraph () {
1096+
return `
1097+
Dear Rod,
1098+
1099+
This is a template literal string that's indented
1100+
four spaces. However, you may have expected for it
1101+
to be not indented at all.
1102+
1103+
Nico
1104+
`
1105+
}
1106+
----
1107+
1108+
While not ideal, we could get away with a utility function to remove indentation from each line in the resulting string.
1109+
1110+
[source,javascript]
1111+
----
1112+
function unindent (text) {
1113+
return text
1114+
.split('\n')
1115+
.map(line => line.slice(4))
1116+
.join('\n')
1117+
.trim()
1118+
}
1119+
----
1120+
1121+
Sometimes, it might be a good idea to pre-process the results of interpolated expressions before inserting them into your templates. For these advanced kinds of use cases, it's possible to use another feature of template literals called tagged templates.
10661122

10671123
==== 2.5.3 Tagged Templates
10681124

@@ -1126,7 +1182,7 @@ console.log(text)
11261182
// <- 'Hello MAURICE, I am THRILLED to meet you!'
11271183
----
11281184

1129-
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.
1185+
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.
11301186

11311187
[source,javascript]
11321188
----
@@ -1225,6 +1281,35 @@ console.log(i)
12251281
// <- i is not defined
12261282
----
12271283

1284+
Given +let+ variables declared in a loop are scoped to each step in the loop, the bindings would work as expected in combination with an asynchronous function call, as opposed to what we're used to with +var+. Let's look at concrete examples.
1285+
1286+
First, we'll look at the typical example of how +var+ scoping works. The +i+ binding is scoped to the +printNumbers+ function, and its value increases all the way to +10+ as each timeout callback is scheduled. By the time each callbacks run -- one every 100 milliseconds -- +i+ has a value of +10+ and thus that's what's printed every single time.
1287+
1288+
[source,javascript]
1289+
----
1290+
function printNumbers () {
1291+
for (var i = 0; i < 10; i++) {
1292+
setTimeout(function () {
1293+
console.log(i)
1294+
}, i * 100)
1295+
}
1296+
}
1297+
printNumbers()
1298+
----
1299+
1300+
Using +let+, in contrast, binds the variable to the block's scope. Indeed, each step in the loop still increases the value of the variable, but a new binding is created each step of the way, meaning that each timeout callback will hold a reference to the binding holding the value of +i+ at the point when the callback was scheduled, printing every number from +0+ through +9+ as expected.
1301+
1302+
[source,javascript]
1303+
----
1304+
function printNumbers () {
1305+
for (let i = 0; i < 10; i++) {
1306+
setTimeout(function () {
1307+
console.log(i)
1308+
}, i * 100)
1309+
}
1310+
}
1311+
printNumbers()
1312+
----
12281313

12291314
One more thing of note about +let+ is a concept called the "Temporal Dead Zone".
12301315

0 commit comments

Comments
 (0)