
Overview of JavaScript ES6 features - adriansky
http://adrianmejia.com/blog/2016/10/19/Overview-of-JavaScript-ES6-features-a-k-a-ECMAScript-6-and-ES2015/#.WA4G-3dZebs.hackernews
======
ggregoire
I'm surprised by the state of const/let nowadays.

The well-known good practice: use const by default; use let when it's needed.
At the release of ES6, it was the way to go. But everyday I notice
libraries—and some really famous— that use let everywhere in their docs, or
some really influent developers from Google or Facebook who share samples of
code on Twitter using let when it's not needed [1]. I don't know why. Seems
like most people now think that const is for declaring constants (in the
traditional meaning, like const API_URL) when it's just the normal way to
declare variables that don't need to be reassigned (so basically most
variables).

Dan Abramov said: "some people say const is ugly" [2]. Well, if it's a matter
of appearance...

[1]
[https://twitter.com/addyosmani/status/789126892402204673](https://twitter.com/addyosmani/status/789126892402204673)

[2]
[https://twitter.com/dan_abramov/status/783708858803978240](https://twitter.com/dan_abramov/status/783708858803978240)

~~~
cloakandswagger
Is it just me, or is Javascript (and more generally, all front end technology)
more susceptible to these trivial holy wars?

While I agree that const/let is a useful convention for communicating
mutability, it isn't nearly a big enough deal to warrant the attention it
receives from the community.

It's not just const/let; I rarely make a front end PR that isn't bike-shedded
to death over subjective styling choices, single quotes vs double quotes, etc.
It often feels like conforming to flavor-of-the-week, subjective decrees from
frontend trendsetters is more important than the substantive work that your
code is doing.

~~~
abritinthebay
> Is it just me, or is Javascript (and more generally, all front end
> technology) more susceptible to these trivial holy wars?

\- Tabs vs spaces.

\- Vi vs Emacs

\- Weak vs strong typing

\- where to place {} in block statements

\- where to put commas

No, _programming_ in general is susceptible to these trivial holy wars.

~~~
gotofritz
Vi vs Emancs? Weak vs strong typing?? tabs vs spaces??? where did you get
those??

The ONLY holy war in JS is the semi-colon one

~~~
lmkg
That's what OP is saying: programming has plenty of holy wars that predate
JavaScript.

~~~
gotofritz
You are right, I misread his comment

------
AgentME
The most interesting part about template strings was skipped over: tagged
template literals. You can prefix a template string with a function which will
get called with the list of string parts and the values passed in ${...}
parts, and then it's up to the function to choose how to join the values up
into the resulting string (or hell, you could make it return something besides
a string if you want). The function can even access the raw version of the
string containing any backslash escapes in it as-is. The default `String.raw`
function is handy if you're writing something like an SQL query with a few \
characters that need to be in the final query. Both of these strings are the
same here:

    
    
        const a = "SELECT id FROM foo WHERE name CONTAINS r'\\n'";
        const b = String.raw `SELECT id FROM foo WHERE name CONTAINS r'\n'`;
    

You could even assign `String.raw` to a variable first, and then make strings
look like raw string literals of other languages:

    
    
        const r = String.raw;
        const s = r`SELECT id FROM foo WHERE name CONTAINS r'\n'`;
    

Another good use of template strings is automatic HTML encoding (with a small
module of mine on npm): [https://www.npmjs.com/package/auto-
html](https://www.npmjs.com/package/auto-html)

~~~
CGamesPlay
How does this work? I can't find any examples and I also don't really
understand what mechanism makes your npm module work.

~~~
AgentME
A tagged template literal is just a special ES6 syntax for calling a function
with a specific set of arguments. You could pass a function which returns all
of the arguments as an array to see what's passed in. Try the following in the
console of a modern browser:

    
    
        function log(...args) { return args; }
        log `abc ${'blah'} fooo\n ${12+3} bar`;
    

Or you could even shorten the above down to this:

    
    
        ((...args)=>args) `abc ${'blah'} fooo\n ${12+3} bar`;
    

The expression will evaluate to this:

    
    
        [["abc ", " fooo\n ", " bar"], "blah", 15]
    

The first argument is an array of the parts of the literal text, and then the
rest of the arguments are the values that were passed in. Additionally, the
first argument (the array of string parts) has the `raw` property set to point
to an array of string parts with the backslash escapes uninterpreted.

Here's an example re-implementation of `String.raw`:

    
    
        function raw({raw}, ...values) {
          const parts = new Array(raw.length*2-1);
          parts[0] = raw[0];
          for (let i=0, len=values.length; i<len; i++) {
            parts[2*i+1] = values[i];
            parts[2*i+2] = raw[i+1];
          }
          return parts.join('');
        }

~~~
adriansky
Tagged templates look interesting. It's an overlooked feature that not many
people know about

------
hzoo
For those using Babel already or want to use ES6+ on a set of supported
browsers: we have started work on [https://github.com/babel/babel-preset-
env](https://github.com/babel/babel-preset-env). Would appreciate more
testing!

It allows passing in a set of supported browsers and transpiling what is
required using the lowest common denominator env (uses
[https://github.com/kangax/compat-table](https://github.com/kangax/compat-
table) for data).

    
    
      // .babelrc with preset options
      {
        "presets": [
          ["env", {
            "targets": {
              "chrome": 52,
              "ie": 11,
              "browsers": ["last 2 versions", "safari 7"]
            }
          }]
        ]
      }
    

If you have questions, ask below (or make an issue)

~~~
epmatsw
Wow, this is really excellent. Definitely will give this a shot!

------
smagch
I always turn to an ES6 article on babeljs.io when I check out ES6 features.

[https://babeljs.io/docs/learn-es2015/](https://babeljs.io/docs/learn-es2015/)

One of the features I like is default parameters. I'd like to add a usage that
isn't mentioned in the article. It's really handy to pass optional parameters
since default parameters can be nested.

    
    
        class Hoge {
          foo({active=true, collapsed=false, silent=false}={}) {
          }
        }
        
        let hoge = new Hoge();
        hoge.foo({collapsed: true});

------
sametmax
"you can start using it right now" if you don't care about IE8, IE9, IE10, and
many mobile browsers and are willing to ignore 20% of your customers.

e.g: [http://caniuse.com/#search=let](http://caniuse.com/#search=let)

const does not have block scope in those browsers either, but will work,
adding to your debugging confusion.

template literals and multiline string has no IE support at all (you need
edge: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Template_literals)) so you can forget most
most enterprise clients

Similar things are missing for most features from the article.

I wonder how many JS dev have to answer to actual customers because none of my
clients in the last decade who would have accepted to have a possible failure
on 1/5 of their visitors. Are they all bloggers or working in hype start ups ?

~~~
ggregoire
We use Babel to compile ES6/ES7/ES8 to ES5.

[https://babeljs.io](https://babeljs.io)

~~~
sametmax
It's not what the article is about. The article is obviously talking about
native ES6 features, otherwise it would advertise es7 features as well and
advise to use transpilers.

~~~
Klathmon
There's no reason why someone using babel needs to use ES2016+ features, they
can stick to ES2015 just like this article.

I'd actually recommend avoiding the still-not-standardized features as you'll
have less/no change when it lands in browsers.

~~~
Can_Not
I looked at the prospects of starting a React, Aurelia, or VueJS projects a
few days ago and a year ago. Anyone who wants to wait to upgrade to these new
things will be really happy to see how much nicer these things get every year.
Tooling and starter kits just keep getting better, and best of all, you could
probably wait a long time to switch and miss out on nothing important.

------
my123
On the web browser side, I don't recommend using ES6 yet, without any kind of
fallback. Internet Explorer 11 is still used, as are devices on older iOS
versions. (without counting people using the default browser on pre-Lollipop
Android)

~~~
fenomas
Also - for anyone writing code where performance matters, the question isn't
when browsers _support_ the syntax, it's when each JS engine's optimizations
support it.

E.g.: until some months ago just putting "let foo" into a function would cause
V8 to bailout (meaning the whole function gets executed slowly, even if the
actual let statement gets removed as dead code).

Unfortunately I've never found any good references on the optimizability of
ES5+ features, so I've been avoiding them so far.

~~~
acdha
This is a real concern, but it definitely carries the usual caveats about
premature optimization and needing to measure regularly to confirm that it is
a real concern and that the performance landscape hasn't shifted since the
last time you measured it.

The best suite I've seen is [https://kpdecker.github.io/six-
speed/](https://kpdecker.github.io/six-speed/) which measures node and the
various modern browsers which Sauce Labs supports and appears to be run semi-
regularly.

~~~
fenomas
That is a great reference, but in general I don't find myself caring much
about the raw performance of individual statements that way. My concern is
that this or that new syntax will prevent a function from getting inlined, or
prevent the engine from guessing type information it otherwise would have
guessed, or whatever - just because those bits of the optimizing compiler are
newer and less robust.

~~~
acdha
I'd assume the author would be receptive to pull requests for things like the
`let` deoptimization.

~~~
fenomas
`let` doesn't deoptimize anymore - actually V8 has made great strides here,
and a lot of new syntax will go through the optimizer. More generally though,
I wouldn't think the stuff I'm worrying about would show up in
microbenchmarks.

------
zelias
While I'm a big believer in most of the ES6 changes (arrow functions!
let/const! classes! generators!), I am not a big fan of many of the new
destructuring features. They can actually make your code less approachable if
you don't already know what's going on.

~~~
i__believe
Exactly, and this is a big problem where I work. I believe code should be
readable, even by those with only cursory knowledge of the language. Object
shortcuts is also a problem I think. For example, I had a method like this:

const getObj = (id, store) => { return { id: id name: store.something.name };
};

The linter gave an error on it because I used {id: id}. It was like the linter
was trying to make my code harder to read.

I think es6 in the wrong hands quickly falls prey to the problems of
ruby/scala where it can become incredibly terse and hard to parse unless you
are used to the author's particular style.

~~~
gidan
You know instead of:

    
    
      const getObj = (id, store) => { return { id } }
    

You could write:

    
    
      const getObj = (id, store) =>  ({ id })

~~~
i__believe
I'm pretty sure that's a good illustration of my point.

~~~
dwaltrip
This is a matter of personal preference.

I find `return` to be quite distracting and annoying for a small function that
spans part of a line, while you and some others may prefer the explicitness of
the `return` keyword.

I would agree that nested destructuring should be used quite cautiously. Code
legibility is incredibly important to the success of any serious project.

------
bpicolo
> Because even though the if-block is not executed, the line 4 still redefines
> var x as undefined.

This is because of hoisting. Not quite right as described.

~~~
fenomas
Yeah, that example should be changed - the "before" version isn't code anyone
would write on purpose, and which JSHint/JSLint would flag as a bug.

------
kin
Appreciate the article, but this is relatively dated information. While I can
see that many enjoyed the article, many have also been working in ES6 for over
a year now. If you're ready to join, I highly suggest everyone make their way
to [https://babeljs.io/](https://babeljs.io/) and everything it has to offer
resource-wise or tooling-wise.

------
qaq
You might as well use babel and then you can use async/await which makes code
way more readable.

------
iamleppert
"best practices": "use class instead of manipulating prototype directly"

Who comes up with these "rules"? This is not a hard and fast rule.
Manipulating the prototype of an object is not "dangerous".

I'm sick and tired of some loud mouth saying something is dangerous without
explaining why. WHY? Why it it dangerous? Don't talk at me. Provide me a sound
reason and case to justify what you say. Talk is cheap.

It makes me not trust anything else in this article when someone is flippant.

~~~
CGamesPlay
[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)

This has some warnings at the top as to why.

~~~
hajile
__proto__ !== prototype

One points to the parent of an object and the other points to the object's
prototype (which in turn has it's own `__proto__ property). Accessing
`prototype` is just fine, but if you want to access `__proto__` then you
should use `Object.create()` instead.

------
Roboprog
Ugh. All this "make Javascript like Java" stuff needs to stop.

Cool stuff: Tail call elimination. Arrow functions. Assignment spread for
multiple return values and "rest" / default parameters. Proxying (combined
with computed get/set on properties) for easy decoration.

Classes and let: meh.

~~~
Meegul
Let is a game changer imo. In the world of tens of dependencies, knowing that
your variables are scope restricted reduces your cognitive load. It's one less
thing that can go wrong.

I agree with you on classes, but that's probably more because I've never been
a big fan of OO in practice. It doesn't really seem to have seen much use in
the greater js ecosystem though, unlike let/const.

~~~
SHOwnsYou
Honest question here ---

What is the difference between let and global variables? There are hundreds of
articles written about the doom associated with PHP globals, but let appears
to be universally lauded. I must be missing something, but I can't tell where.

~~~
Meegul
It's spelled out pretty well in the article. But if you want another example,
consider these two code blocks:

    
    
      var foo;
      var bar;
      { 
        let foo = "hello";
        var bar = "world";
      }
      console.log(foo);
      console.log(bar);
    

This produces:

    
    
      undefined
      world
    

The reason being that the `let` statement restricted that variable to the
block it was in (defined by the { and }). `var` declares the variable
globally, allowing it to be accessed outside of the {}.

We prefer now to use `let` and `const` over `var` because it doesn't pollute
the global namespace. With the asynchronous nature of Javascript, it's
theoretically possible for you to declare a variable with `var`, assign it a
value, then immediately use that value and find that it's different than what
you expected because of another function using the same variable name. This
isn't possible with `let`.

~~~
SHOwnsYou
From the article--

let x = 'outer';

function test(inner) {

    
    
      if (inner) {
    
        let x = 'inner';
    
        return x;
    
      }
    
      return x; // gets result from line 1 as expected
    

}

test(false); // outer

test(true); // inner

This makes it seem like let creates global variables. Why would you want to
return a variable from outside the function? Doesn't that create massive
overhead in terms of keeping track where variables are initially set? Easy to
understand in this example, but what if let x = 'outer'; is defined at the top
of a 5000 line script and this function appears near the bottom?

Edit: Turns out I don't know how to format code. This is in the first example
of section 3.1 Block Scope Variables.

~~~
Meegul
If you were to then reference 'x' from another block of code, say in another
<script> element in the case of web development, 'x' would not be a defined
variable, whereas with 'var', it would be.

This is mostly just a case of 'let' restricting a variable to the block it is
in, and the child blocks. In your example, `let x = 'outer';` is sort of
acting like a global variable, but the importance is that if another script
were to be running, it could not access that instance of 'x'.

~~~
Roboprog
Ehw. Yeah, I sort of assumed that you had a top level function / IIFE (in a
.js file, FWIW) in which the var's were nested.

Somebody writing stuff, into the global namespace, directly in <script> tags,
has bigger problems :-)

------
VeejayRampay
I have a question:

What does `for element of arr` buy me over `arr.forEach(element => ...)`

I don't find the for...of syntax particularly appealing or useful, but I might
be missing something. Is it a matter of preference?

~~~
addisonj
for...of isn't only for arrays. Anything that implements the Symbol.iterator
functionality can use for..of, which is pretty nifty for some custom classes
and also includes things like the new Map and Set collections, see:
[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Iteration_protocols#iterable)

However, even in just arrays there is arguably a benefit. Namely, an extra
function being created and invoked with forEach. While in a JITing compiler,
the performance difference between for...of and forEach might be negligible
(or non existent), you can't always be sure what the JIT is going to do. For
hotspots, I would probably prefer for..of

~~~
bzbarsky
If you're not in a JIT, for-of performance is going to be terrible too.
Instead of creating a single function (which may not happen _anyway_ in the
non-jit case, depending on how it's implemented) you now have to create an
iterator result object for every single thing you get out of the iterator.

In a JIT, forEach is actually _easier_ to optimize well (just need to inline
the callback function, though of course that can fail for various reasons)
than for-of (need to inline the calls to next() on the iterator, need to do
escape analysis on the return value of next(), need to do scalar replacement
on the return value of next; note that this is a strict superset of the work
needed to optimize forEach).

for-of can be nicer to read, and can work on arbitrary iterables. Those are
its key strengths. Performance just isn't, unfortunately.

------
pluma
I gave a more complete overview of ES6 (and ES2016 and so on) features at a
user group last month. Slides:

[http://files.meetup.com/11421852/WhatsNewInJavaScript.pdf](http://files.meetup.com/11421852/WhatsNewInJavaScript.pdf)

The slides are mostly code examples and I tried to go for completeness rather
than detail, so there are some mentions you don't normally see in these
overviews (e.g. the article doesn't mention proxies).

------
firethief
Equally spacing the points on the timeline may make for an aesthetic image,
but it fails to illustrate the author's point. "As you can see, there are gaps
of 10 and 6 years between the ES3, ES5, and ES6. The new model is to make
small incremental changes every year." No, we can't see. In that pretty
graphic, ES5->ES6 is exactly the same distance as ES6->ES7.

------
mooveprince
If someone wants to dig more on ES5 vs ES6 , check this presentation (use side
arrow for navigation)
[http://coenraets.org/present/es6/#1](http://coenraets.org/present/es6/#1)

~~~
Roboprog
This one is a useful reference, as well:
[http://es6-features.org/#Constants](http://es6-features.org/#Constants)

------
ciju
Probably add pointers to where the images were taken from.

Ex:

[https://kangax.github.io/compat-table/es6/](https://kangax.github.io/compat-
table/es6/)

------
viebel
Great article!

It would be fantastic to make all the code snippet interactive with the klipse
plugin.

[http://blog.klipse.tech/javascript/2016/06/20/blog-
javascrip...](http://blog.klipse.tech/javascript/2016/06/20/blog-
javascript.html)

------
stigi
If you want to learn ES6 I highly recommend the Tower of Babel interactive
tutorial: [https://github.com/yosuke-furukawa/tower-of-
babel](https://github.com/yosuke-furukawa/tower-of-babel)

------
jnasc
What about import from? (modules)

~~~
ggregoire
In my opinion it's the biggest improvement from ES6. However, you still need
Babel to use this feature, even in Chrome/Firefox.

For those interested:

import: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Statements/import)

export: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Statements/export)

------
goatlover
Some of these features are really nice, but JS is on a path to become as
complex as C++.

~~~
warlox
That's the natural result of being unable to remove any features to maintain
legacy compatibility.

~~~
Klathmon
Well unlike the majority of C++ warts, JS is doing a very good job of "hiding"
it's ugly parts with things like "use strict"

Things like `with` and a bunch of ugly parts were hidden with the introduction
of "use strict", and i'm more than confident it will happen again in the
future with something similar that can let you "opt in" to an even stricter JS
that leaves behind the "current" warts of javascript in favor of much better
ways.

------
drivingmenuts
Can someone smarter than me (not a high bar) explain why they didn't just fix
var, rather than introducing let?

~~~
ChemicalWarfare
backward compatibility would be one reason.

------
lacostenycoder
Helpful article. Small typo on section 3.5. shouldn't 'construtor' ==
'constructor' ?

~~~
bluepnume
Javascript's weak comparison operators aren't _that_ bad.

------
pwython
Can anyone recommend books or online courses that teach ES6 for someone just
starting out with JS?

~~~
waylandsmithers
The book from the "You Don't Know JS" series is very thorough:
[https://github.com/getify/You-Dont-Know-
JS/tree/master/es6%2...](https://github.com/getify/You-Dont-Know-
JS/tree/master/es6%20%26%20beyond)

------
Mchl
What's interesting is that the author apparently has a QUERTY keyboard
layout...

~~~
adriansky
ha, I do

------
z3t4
var's function scope is a feature! You don't have to place variable
declarations in the header! (they are hoisted) Placing the var declarations
where they are used makes the code easier to understand.

The point of constructor functions is not having to write _new_. So classes
does nothing besides syntactic sugars over the prototype system, witch
actually makes it more complicated and the code harder to maintain.

Async programming _is_ hard, but not because of callbacks. Promises is just a
wrap around callbacks, witch just adds complexity and more boilerplate. It
will get better with async/await but I will still prefer simple callbacks.

Arrow functions are very nice for one liners, but will ruin your code if you
use them everywhere instead of named functions. You should always name your
closures, then it's easier to debug and lift them out.

~~~
WorldMaker
Arrow functions get auto-named in many browsers based on how they are used.
This auto-naming is actually being somewhat standardized between browsers and
means there is no difference between anonymous-style function () {} and arrow
functions.

Promises are more than just a wrapper around callbacks because they also
standardize behavior between "stacks" of callbacks, by instead "chaining" them
and creating a standard infrastructure for things like error propagation down
a chain. That error propagation and the ability for simple action chaining is
worth having over "simple" callbacks, even without the syntactic sugar of
async/await.

let/const have similar benefits to function hoisting in that you don't need to
declare let/const variables until when you use them. In this case the runtime
behavior throws an exception if you try to use them before they are declared
(in the so-called hoisting dead zone).

~~~
z3t4
Promises spreads like a virus so that all asynchronous functions eventually
end up returning a Promise. They are hard to understand and it's easy to
forget handling errors or return values. I think callbacks are much easier to
understand and get right using named functions and closures.

If you want to call everything in serial and wait between each step, why not
make it synchronous instead of .then chaining ?

~~~
WorldMaker
There are other high level operations (combinators) with Promises beyond just
.then() chains: Promise.all(), Promise.race() out of the box of the spec;
others from various libraries. Doing the equivalent with raw callbacks is much
more complicated.

The "magic" that Promises bring to code is that they "just look serial" with
.then() chains. That's part of the point of Promises and that's part of the
infrastructure what powers the ability to write async/await code. Just because
it looks nice and serial doesn't mean it is synchronous. (In High Functional
speak, Promises are the Continuation monad, and the near isomorphism with
synchronous code (especially async/await) is a wonderful product of
standardizing the monad.)

Which is to say: tl;dr: Promises spreading like a virus is a feature, not a
bug.

------
caub
uhhh edge still hasn't destructuring

------
albertTJames
[a, b] = [b, a];

Great !

------
neximo64
Using const and `splice` breaks the rules:

const info = [1,2,3,4]

const newInfo = info.splice(2);

'info' has changed

~~~
josephg
The const keyword makes the object _reference_ constant. It doesn't make the
object's _value_ constant. You can change the _contents_ of 'info'
(info.push(5) is fine). You just can't change which object the variable points
to. (info = [] will throw).

If you know C/C++, the code 'const info = []' makes 'info' a _constant pointer
to a list_ not a _pointer to a constant list_.

If you want to stop a variable from being changed, use Object.freeze() -
[https://developer.mozilla.org/en/docs/Web/JavaScript/Referen...](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)

~~~
samcodes
This was what I came to comment on; when introducing ES6 features, this always
trips people up. Thanks for "constant pointer to a list, not pointer to a
constant list", I will use that next time I explain this.

This also means that objects defined with const can be mutated:

const x = { y: 2 }; x.y = 3;

Doesn't error. However with types that are immutable, like numbers and
strings, const really is a constant: const HELLO = "hi" will never change.

------
mattmanser
_destructing is very useful and encourage good coding styles_

Is it? Personally I'd say that was bad code. What so wrong with using the
original objects?

Putting aside the need to variable swap once a year or so, all the other
examples look really confusing to me and unclear what they're doing. The `Deep
Matching` especially.

~~~
ubertaco
It's really nice for when you have to do operations where you want a "tuple"
in Javascript.

Consider the case of finding all companies along with their hires from the
last week, but only if the company _has_ a hire from the last week:

    
    
        companies.map(c => [c, employeeStorage.getEmployees(c)])
                 .map(([company, employees]) => [company, employees.filter(e => e.hireDate > aWeekAgo)])
                 .filter(([company, employees]) => employees.length > 0)

