Exploring ES6: Upgrade To The Next Version Of JavaScript By Dr. Axel Rauschmayer
I love JavaScript. For me, JavaScript has always been a joy to work with. I never understood all the "Good parts" / "Bad parts" drama - once you get your head wrapped around closures and what "this" references, the rest is just limited by your imagination******. But, my love of JavaScript, and of ES5 in particular, has probably held me back. So, after much goading by people like Jonathan Rowny and Scott Rippey, I've decided to bring my understanding of JavaScript into the modern day with "Exploring ES6: Upgrade To The Next Version Of JavaScript" by Dr. Axel Rauschmayer.
** NOTE: I'm not saying that JavaScript is "easy," only that it is "simple." Building complex application with JavaScript is hard and something that I am, at best, mediocre at doing. But, I'm learning new things every day!
I've been following Dr. Axel Rauschmayer's blog for years now. And, I'm mostly convinced that he's just living tissue over a metal endoskeleton. His understanding of JavaScript is deep and his attention to detail is laudable; so, I was half expecting his book, "Exploring ES6," to make my head hurt. I was not disappointed.
I read Exploring ES6 cover-to-cover, as I try to do with most technical books; and, by the time I was done, my brain was fully saturated. Actually, it was saturated before I even got that far. In fact, I mostly skimmed the chapter on Proxies and only half-read the chapter on Regular Expressions (and you know how much I love Regular Expressions).
Now, don't get me wrong - it was awesome! Not only does Rauschmayer walk through the new features of JavaScript, he does so with many examples. And often times, his examples will build towards a solution by evolving old concepts into new concepts. This way, you can see how ES6 goes about solving old problems in new and exciting ways.
One of the main reasons that I wanted to read this book was because I had no idea what Generators were, other than that they were the new hawtness. Luckily, Exploring ES6 has an entire chapter on Generators (and one on Promises that dove-tails nicely with it). I'm still generally confused about what they do; but, the book covers them in great depth, demonstrating that they can both emit values (via yield) and accept values (via .next()). This makes them especially exciting when used with a workflow layer that can wrangle data between Promises and Generators, completely transforming the way asynchronous control-flow looks and feels.
But, it wasn't all marquee features. A lot of the interesting facts revolved around tiny facets of the language. For example, "const". Now, you know that I'm a "var for life" kind of developer. But, until I read this book, I had no idea that "const" had magical binding properties when combined with for-of iteration. To demonstrate, take look at the output produced by two for-of loops, one with "const" and one with "var":
"use strict";
// Iterate over an array using CONST.
for ( const value of [ 1, 2, 3, 4, 5 ] ) {
setTimeout( () => console.log( "(const) Value:", value ) );
}
// Iterate over an array using VAR.
for ( var value of [ 1, 2, 3, 4, 5 ] ) {
setTimeout( () => console.log( "(var) Value:", value ) );
}
As you can see, both loops are doing the same thing. But, when we run this code through Node.js, we get some surprising - at least to me - results:
(const) Value: 1
(const) Value: 2
(const) Value: 3
(const) Value: 4
(const) Value: 5
(var) Value: 5
(var) Value: 5
(var) Value: 5
(var) Value: 5
(var) Value: 5
Notice that all values in the "var" loop are the same while the values produced by the "const" loop are unique. This is because the "const" variable is actually being re-defined with each iteration of the loop.
I'll still use "var" for the vast majority of use-cases; but, I'll happily use it in situations like this where the "magical re-binding" actually creates practical value. As far as I'm concerned, Dr. Rauschmayer is the first person I've seen who's demonstrated real-world value of the "const" declaration.
Though, of course, you could argue that this magical re-binding makes the code surprising; and, following the Principle of Least Surprise, perhaps it should be avoided. Hmmm, much food for thought.
In the end, Exploring ES6 is a great book, offing insights both large and small. It's definitely more information than I could absorb in a single pass. At the very least, I need to re-read that chapter on Generators and Proxies. If you really want to dig into how ES6 works, I highly recommend it.
Want to use code from this post? Check out the license.
Reader Comments
@All,
Just a quick note that the Node.js demo about var-vs-const - the same behavior is also achieved with `let`. Meaning, `let` and `const` both re-define the variable with each loop iteration in a for-of loop.
That said, if you were to use a for-index loop, with `let`, you get the same behavior that `var` would have:
for ( let i = 1 ; i <= 5 ; i++ ) {
. . . . setTimeout( () => console.log( "(for-i let) Value:", value ) );
}
... would output:
(for-i let) Value: 5
(for-i let) Value: 5
(for-i let) Value: 5
(for-i let) Value: 5
(for-i let) Value: 5
... and that's because the `let` value isn't be re-defined with each iteration, just updated. And, hence, has the same behavior as `var`.
So, the magic of the rebinding is specific to the for-of loop.
My problem has less to do with understanding ES6 generators and other 'improvements' than knowing when to reach for them. Destructuring is awesome and useful, but generators? Not as much... For me anyway, but I'm probably just missing the point of them or I don't write sophisticated enough apps.
@Chris,
Yeah, Generators are the hardest thing for me to wrap my head around. I've read the Generators chapter twice now, and looked through the docs on MDN (Mozilla Developer Network) and it's still really confusing. I think one of my next posts will have to be a little trial and error with Generators as I don't think I'll really "get it" until I try to write a little bit of it out.
But, I agree, its hard to know when to reach for these kinds of solutions. And, for me, the biggest problem with that is that if I don't know when to use them, I won't use them; and then I'll slowly forget that they even exist. And then all hope is lost :)
Take ColdFusion - I'm still on ColdFusion 10 at work, which is a full 2 versions behind the current version. So, I'm slowly (or probably more quickly) forgetting everything that I learned about the last 2 releases simply because I don't have the hands-on need for them.
Practice. practice. practice!
@All,
Here's a fun post on Template Literals, much of which I learned from reading this book:
www.bennadel.com/blog/3120-writing-conditional-sql-statements-using-nested-tagged-template-literals-in-node-js.htm
In that post, I look briefly at using "tagged" template literals, which Ruaschmayer talks about at length.
for ( let i = 1 ; i <= 5 ; i++ ) {
. . . . setTimeout( () => console.log( "(for-i let) Value:", value ) );
}
It's just matter of understanding how JS engine works in browser. JS is one thread step-by-step language and setTimeout (like others non blocking instructions) is "external" browser API so it doesn't go straightly to stack but to other "jobs list container". When stack goes empty then all other jobs are pushed to stack.
BTW This is a reason why setTimeout(function(), 100) is just minimal time to function inside settimeout. When you have a heavy work on stack it can be 2000ms for example.
@Greg,
"It's just matter of understanding how JS engine works"
... true :) But, that doesn't always mean that it's very intuitive. Meaning, it's not entirely obvious that a for-index loop and a for-of loop update the value in different ways. Or specifically that one updates the value and one re-binds the value. For that, you really have to understand exactly how the JS engine works.
I'm looking forward for your further investigations in ES6, Ben!
@Chris
ES6 Generators are coroutines. And coroutines give us the tools to implement program-interpreter collaborating pairs, among other similar things.
For day-to-day, maybe it's not as useful to use directly. For library writers, it's an amazingly powerful tool. E.g. implementing async/await (see http://bluebirdjs.com/docs/api/promise.coroutine.html)
@Ben,
I just tried the 'for-i let' code in the console and got the same output as the 'for-of let' code
for ( let i = 1 ; i <= 5 ; i++ ) {
setTimeout( () => console.log( "(for-i let) Value:", i ) );
}
and got this output:
(for-i let) Value: 1
(for-i let) Value: 2
(for-i let) Value: 3
(for-i let) Value: 4
(for-i let) Value: 5
I'm still learning this stuff myself so it could be that I got hold of the wrong end of the stick altogether, but from what I understand let will create a new binding in both situations.