Thoughts on ECMAScript 6 and new syntax

I am, just like many in the JavaScript world, watching anxiously as ECMAScript undergoes its next evolution in the form of ECMAScript 6. The anxiety is a product of the past, when we were all waiting for ECMAScript 4 to evolve. The ECMAScript 4 initiative seemed more like changing JavaScript into a completely different language that was part Java, part Python, and part Ruby. Then along came the dissenting crowd, including Douglas Crockford, who brought some sanity to the proceedings by suggesting a more deliberate approach. The result was ECMAScript 5, which introduced several new capabilities to the language without introducing a large amount of new syntax. The focus seemed to be on defining the so-called “magical” parts of JavaScript such as read-only properties and non-enumerable properties while setting the path forward to remove “the bad parts” with strict mode. The agreement was that TC39 would reconvene to address some of the larger language issues that were being solved in ECMAScript 4 and punted on in ECMAScript 5. That process began to create the next version of the language code-named “Harmony”.

We are now quite a bit further along the development of ECMAScript 6 so it’s a good time to stop and take a look at what’s been happening. Obviously, the evolution of any language focuses around adding new capabilities. New capabilities are added in ECMAScript 5 and I fully expected that to continue in ECMAScript 6. What I didn’t expect was how new capabilities would end up tied to new syntax.

Good new syntax

I’ve had several conversations with people about various ECMAScript 6 features and many have the mistaken belief that I’m against having new syntax. That’s not at all the case. I like new syntax when it does two things: simplifies an already existing pattern and makes logical sense given the rest of the syntax. For example, I think the addition of let for the creation of block-scoped variables and const for defining constants make sense. The syntax is identical to using var, so it’s easy for me to make that adjustment in my code if necessary:

var SOMETHING = "boo!";
const SOMETHING = "boo!";
let SOMETHING = "boo!";

The cognitive overhead of using new keywords with the familiar syntax is pretty low, so it’s unlikely that developers would get confused about their usage.

Likewise, the addition of the for-of loop is some syntactic sugar around Array.prototype.forEach(), plus some compatibility for Array-like items (making it syntactic sugar for Firefox’s generic Array.forEach()). So you could easily change this code:

var values = [1, 2, 3, 4, 5, 6];
values.forEach(function(value) {
    console.log(value);
});

Into this:

var values = [1, 2, 3, 4, 5, 6];
for (let value of values) {
    console.log(value);
}

This makes complete sense to me. The syntax is very similar to the already existing for and for-in loops and mimics what’s already available with Array.prototype.forEach(). I look at this code, and it still looks like JavaScript, and that makes me happy. Even if I choose not to use the new syntax, I can still pretty much accomplish the same thing.

Bad new syntax

One of the features of ECMAScript 6 that has received a lot of attention by the so-called “fat arrow” functions1. This appears to be an attempt to solve several problems:

  • this binding – The desire to more easily specify the value of this Within a function. This is the problem that Function.prototype.bind() solves.
  • Avoid typing “function” – For some reason, people seem to hate typing the word “function”. Brendan Eich himself has said that he regrets using such a long word. I’ve never really had a problem with it or understood people’s frustration with having to type those characters.
  • Avoid typing parentheses, braces – Once again, the syntax seems to be the issue. And once again, I just don’t get it.

So essentially this:

function getName() {
     return this.name;
}

var getWindowName = getName.bind(window);

Becomes this:

var getWindowName = () => this.name;

And this:

function getName(myName) {
     return this.name + myName;
}

var getWindowName = getName.bind(window);

Becomes this:

var getWindowName = myName => this.name + myName;

I know I’m probably alone on this, but I don’t think the syntax is clear. If there are no arguments to the function, then you need to provide parentheses; also, if there is more than one argument, you need parentheses. If there’s just one argument, then you don’t need the parentheses. With me so far?

If you want to return an object literal from one of these functions, then you must enclose the object literal and parentheses:

let key_maker = val => ({key: val});

Then if you want to do more than one thing in the function body, you need to wrap it in braces and use a return Like you would in a regular function:

let sumIt = (val1, val2) => {
    var sum = val1 + val2;
    return sum;
};

And don’t be confused into thinking these functions act like all other functions. There are several important differences between functions declared using the fat arrow syntax and functions declared in the more traditional way:

  • As mentioned previously, the value of this is static. It always takes the value of this for the enclosing function or global scope.
  • You can’t use new with a fat arrow function, it throws an error.
  • Fat arrow functions do not have a prototype property.

So not only are arrow functions trying to solve a bunch of problems, they also introduce a bunch of side effects that aren’t immediately apparent from the syntax. This is the type of new syntax that I don’t like. There’s a lot that goes on with arrow functions that is unexpected if you think that this is just a shorthand way of writing functions.

What’s more, I don’t know how to read this out loud. One of the things I’ve always liked about JavaScript is that it says what it does so I can actually read the code out loud and it makes sense. I have no idea how to pronounce that arrow function. “Let variable equal to a group of arguments that executes some statements?” It just doesn’t work for me. In some ways, this is the sort of problem you end up with when you try to solve multiple problems with one solution. There are a lot of rules to remember with this syntax and a lot of side effects to consider.

Just for argument sake, if someone asked me what sort of new syntax I would suggest for sugaring Function.prototype.bind(), I would choose something along the lines of this:

// My own attempt at sugaring Function.prototype.bind() - not ES6
function<window> getName() {
    return this.name;
}

This sort of syntax looks familiar to me while actually being new. I would read it as, “define a function in the scope of window called getName.” The idea is that this would always end up equal to window. Granted, the solves only one of the problems that arrow functions try to solve, but at least it says what it does.

Ugly new syntax

There are other features in ECMAScript 6 that make me feel like JavaScript is becoming an ASCII art language. For some reason, instead of adding new capabilities with already existing syntax, the specification adds new capabilities only with new syntax. What puzzles me the most about this is that these capabilities are those that already exist in other languages in some form.

Case in point: quasis (aka quasi-literals)2. Quasis seem to be a solution for many different problems in JavaScript. As best I can tell, quasis are supposed to solve all of these problems:

  • String formatting – JavaScript has been missing this for a long time. Languages such as C# and Java have a method called String.format() that allows simple symbol substitution in strings. Quite honestly, an implementation of that in JavaScript would make me incredibly happy (Crockford has actually proposed something along those lines3).
  • Multiline strings – For some reason, people feel like there needs to be a standard way of doing multiline strings that isn’t what’s already implemented using a backslash before a newline character.
  • HTML escaping – This is also something JavaScript has been missing for a long time. While it has shipped with URL escaping for quite a while now, HTML escaping has been noticeably missing.

Quasis use the backtick symbol (`) to indicate a section of code that requires variable substitution. Inside of the backticks, anything contained within ${...} will be interpreted as JavaScript in the current context. The basic syntax is as follows:

someFunc`Some string ${value}`;

The idea is that someFunc is the name of a function (a quasi handler) that interprets the value enclosed in the backticks. There are several use cases in the proposal, such as the creation of a safehtml quasi handler for doing HTML escaping and a msg quasi handler for performing localization substitutions. The ${value} is interpreted as the value of a variable named value. You can also have multiple lines within the backticks:

someFunc`Some string ${value}.
And another line.`;

I’m not going to go into all of the ins and outs of quasis, for that you should see Axel Rauschmayer’s writeup4. If you read through his post, you’ll see that this is a fairly involved solution to the already-solved problems I mentioned earlier. What’s more, it doesn’t even look like JavaScript to me. With the exception of multiline strings, the problems can be solved using regular JavaScript syntax. Once again, if it were up to me, this is how I would solve them:

// My take at string formatting - not in ES6
var result = String.format("Hi %s, nice day we're having.", name);

// My take at HTML escaping - not in ES6
var result = String.escapeHtml("Does it cost < $5?");</code>

In these cases, it seems like a bazooka is being used when a water gun would suffice. Adding the capability to format strings and escape HTML is certainly important for the future of JavaScript, I just don’t see why there has to be a new syntax to solve these problems. Of everything in ECMAScript 6, quasis is the feature I hope dies a horrible, painful death.

Conclusion

I’m admittedly a bit of a JavaScript purist, but I’m willing to accept new syntax when it makes sense. I would prefer that new capabilities be added using existing syntax and then layer syntactic sugar on top of that for those who choose to use it. Providing new capabilities only with new syntax, as is the case with quasis, doesn’t make sense to me especially when the problems are both well-defined and previously solved in other languages using much simpler solutions. Further, only using new syntax for new capabilities means that feature detection is impossible.

It seems like in some cases, TC 39 ends up creating the most complicated solution to a problem or tries to solve a bunch of problems all at once, resulting in Frankenstein features like arrow functions and quasis. I believe that the intent is always good, which is to avoid problems that other languages have seen. However, the result seems to make JavaScript much more complicated and the syntax much more foreign. I don’t want JavaScript to be Python or Ruby or anything else other than JavaScript.

  1. Arrow function syntax by Brendan Eich
  2. Quasi-Literals
  3. String.prototype.format() by Douglas Crockford
  4. Quasi-literals: embedded DSLs in ECMAScript.next by Dr. Axel Rauschmayer

Comments

  1. Praveen Gunasekara

    Completely agree with you on new syntax which are introduced on ECMAscript6. most of the new syntax will make the code unreadable, which indeed will be the reason for longer turn around times to fix buggy code in a team environment. It makes me think is syntax are the only thing which needed an upgrade for the next version of javascript? was that the best prioritization we could do within the community?

  2. David Bruant

    Have a look at https://github.com/DavidBru...
    The language needs to solve this kind of problem and functions with lexical |this| would be the most intuitive way to go in my opinion.
    Whether the current proposal to address this is good or not is a different concern that is important to discuss, I agree.

  3. Nicholas C. Zakas

    @David - I absolutely agree that the problem needs to be solved, I just don't like arrow functions as the solution.

  4. Justin Long

    Honestly, I see the fat arrow solution as less of a solution to the "this" problem, but more of a solution to the "largeness" of using an anonymous function.

    i.e.

    [1,2,3].map(function(f) { return f*f; })
    vs
    [1,2,3].map(f => f*f);
    vs Eich's
    [1,2,3] map f=>f*f /* very ruby-esque */

    And I agree, do String.format in the same way that Object.keys was done. That makes shimming it easy, and backwards compat. And the edgecase of newlines in string literals is so small...

    Otherwise agreed on the whole piece!

  5. Nicholas C. Zakas

    @Justin - yes, definitely. That's part of my point, it seems like this evaluation was shoehorned into arrow functions.

  6. Ray Bellis

    Oh my, what a crock (most of) those syntax extensions are.

    One of the beauties of JS is the relative simplicity of the _syntax_ of the language. The only hard part for most people is scoping, and this new syntactic sugar is not the answer.

    BTW, does that "for let ... of ... " syntax solve the loop / callback problem? One of the main benefits of ".foreach" is that the callback function automatically fixes the loop variable into the closure's parameters. If I had a pound for every time I've answered the question about loop variables and async callbacks, I'd be, well, slightly better off :)

  7. Hongbo

    very well said, I'm completely agree with you!!!
    this reminds me of Google's Dart which gives nothing help to current javascript.

  8. Jared

    Thanks for the article Nicholas. You've reinforced a lot of opinions that I've had about some of these new syntaxes and features.

    Are you sure you can't feature detect all of these things? For example, with the fat arrow syntax couldn't you try to use the new keyword and see if it fails in a try-catch?

    Regardless, your conclusion really says it all. I agree that new features shouldn't be restricted to new syntax. I also think it was super helpful for you to propose syntax on a few of the items, especially string format. I see no reason why it should be anything more than that.

    Cheers,
    Jared

  9. Ara Pehlivanian

    Thank you, Nicholas, for the writeup. I couldn't agree with it more. You shouldn't make any apologies for being a JavaScript purist. If anything, these proposals feel like a bunch of non-JavaScript developers are trying to impose their views on a language they have yet to fully grasp. I really wish people would stop trying to change the language into something else. It's really irritating.

  10. Adam

    I completely agree with this. The reason why JavaScript was named "Java"Script was because it used a Java (i.e. C) style syntax. This was done to take advantage of the large population of Java and C programmers already out there. Yes, this has lead to problems when Java developers do not realize the difference between Java and JavaScript, but overall it makes JavaScript easy to learn and write for Java developers. Switching to the arrow syntax will lose this advantage and could hurt JavaScript's popularity and readability overall.

  11. Mathias Bynens

    I agree with the sentiment of your post but this doesn’t seem like a very strong argument:

    Further, only using new syntax for new capabilities means that feature detection is impossible.

    How so? It can still be done using a form of eval in a try-catch.

  12. Nicholas C. Zakas

    @Jared - the point of feature detection is to detect a capability before you try to use it. Sure, you could test a function to see if it was created with that arrow syntax or not, but that doesn't buy you much.

  13. Nicholas C. Zakas

    @Mathias - I don't consider intentionally causing errors as feature detection. You should be able to detect the capability without needing to write out code in eval().

  14. Dmitry

    Thanks! Very good article!

    String formatting functions are much better than backticks, because it's API and not language syntax.

  15. Adam

    For what it's worth, I like the your solution for putting the function's fixed scope before the function's name as it feels instinctual. Just as how in obj.func(), obj would be "this", function func () {} reflects that design to me.

  16. Adam

    My greater than and less than around "obj" were removed.

    Just imagine that I'd typed:

    function < obj > func () {}
  17. Eric Wendelin

    I get the sense that a lot of the new syntax in ES6 is driven by coffeescript. Not sure if it's bad, just extreme in some cases.

    Agreed with the sentiment that we're missing additions using existing syntax. I hope the TC-39 can solve that problem soon.

  18. Sergey

    Hey, good article. Agree with everything you mentioned here except of String.escapeHtml - this should not be part of language core, this should be something that browsers implement as extension.
    The best thing in javascript design is that there are only few core concepts which you have to understand and they are reused everywhere in language - which help you learn js faster and build multi-paradigm code. Adding new syntax which doesn't look javascriptish is definitely braking its readability and beauty.

  19. Amit Agarwal

    I completely agree with what you wrote Nicholas. Getting new syntax is the new problem which JavaScript is getting into. Also it makes cross browser development harder because old browser don't understand new syntax. It would've been more useful if new capabilities were added in the existing syntax itself so that any one can use them fearlessly and that way single syntax has lot more fun to uncover. But new syntax's, that too dirty and not looking like JavaScript......really bad!

  20. Daniel

    I've been using lambdas in C# (which uses exactly the same syntax as proposed here) for years, I find lambdas very readable. When using functional programming (e.g. map/filter/reduce instead of loops), there often is one lambda in each line of code, so the additional terseness is very welcome.

    Java 8 will also use arrow syntax to denote anonymous functions: "(int x) -> x * 2"
    So I think it makes that JavaScript does the same - it's just what programmers from those syntactically similar languages will expect.

  21. David Bruant

    "@Mathias – I don’t consider intentionally causing errors as feature detection. You should be able to detect the capability without needing to write out code in eval()."
    => Rule one of feature detection: there is no rule.
    Everything counts, even weird bugs, even undocumented features or even proprietary features, even edge cases and even any combinaison of the previous.

    New syntax features are purposefully designed to break in engines supporting old versions of the language, so eval+try/catch seems to be the most genuine form of syntax detection support.

    "The result was ECMAScript 5, which introduced several new capabilities to the language without introducing a large amount of new syntax."
    => To the best of my knowledge, ES3 and ES5 are almost identical in syntax. The only difference is getters and setters in object literals.
    For the anecdote, eval+try/catch is what Kangax uses in his tables: http://kangax.github.com/es...

    I admit it would be tempting to add a more "legitimate" way to do syntax feature detection, but, how are you guaranteed, as a developer, that this more legitimate way doesn't contain a bug? eval+try/catch seems less likely to "lie" in my opinion, mostly because the parser used in eval is the same that the regular parser. It's the same in the spec, so it's likely to be the same in implementations.
    But that's an interesting discussion to have.

  22. Andreas Goebel

    Thanks Nicholas for putting those issues into words. Personally I do totally agree with most of your points.

    To me it looks like another case of, "where tunnel-vision is going wrong". Also many "syntax improvements" look like people try to modify/optimize things just for the sake of modifying. I just hope there enough smart people left who are able and brave enough to intervene stuff decisions like this.

    Also, talking about a new version of ES, I'd actually vote for methods like a ".format()" to go into the prototype, so we can go like "Hello %s, who are you?".format( name );

  23. Jakub Narebski

    Moreover the quasi proposal doesn't solve all problems with string formatting. What about padding with spaces or zeros to given width? With API approach it would simply be String.format("%02d:%02d", h, m).

    BTW does ES6 solve all problems that you have mentioned in your blog post "When web standards fail us"?, http://www.nczonline.net/bl...

  24. Jennifer

    Those backticks are just wrrrooooonnng!

  25. kid

    Totally agreed on every point you make here especially with fat arrows and string formatting. I really hope this all pans out well.

  26. odedbd

    I feel that you are right on the money on all accounts. Thank you for voicing my feelings in a much more eloquent and detailed way than I feel I ever could. I simply can't read those fat arrow functions, and I hope I won't be forced to get used to them.

  27. Jesús Ambriz

    Excelente artículo!
    Le agregué otros recursos más en:
    http://deprofesoramaestro.b...

  28. sv

    What I don't get is why introduce for-of instead of adopt the "for each" from the E4X (ECMA-357) standard.

  29. Adam

    Agree 100%

  30. ScottM

    I am completely with you on the fat arrow thing. The problem is that changes like this are written by people highly experienced with the language (and who apparently think like computers). They don't take into account how difficult it is for people learning the language to remember what things like that mean. Function is easy. "Look, we're defining a function. See, it says so right here."

    It's the kind of shortcut that experienced users love but that ultimately dooms a language by driving away potential new users. Not that this alone will kill JavaScript, but continued effort in that direction likely will.

  31. Roy Tinker

    Nick, I totally agree with you here. The "fat arrow" lambda syntax seems to be taken directly from C# 3.0+, when Microsoft introduced lambda expressions into the language's syntax. They work very well within the C# syntax and with Microsoft's LINQ functional extensions -- as of v3.0, C# supports functional programming remarkably well, supporting all sorts of collections (both local and remote).

    But to bring C# into Javascript is misguided. I think the people behind this are probably used to the C# syntax, and perhaps aren't thinking "in javascript" when designing language improvements.

    Roy

  32. Nicholas C. Zakas

    @Sergey - HTML escaping should definitely be part of the core language. Remember, JavaScript is used not just in the browser but also on the server. HTML escaping is a common use case for both, arguably more common than URL escaping which is already part of ECMAScript.

  33. Nicholas C. Zakas

    @Daniel - If the arrow functions were just simply anonymous functions, I would have less of an issue with them. As I said in the article, my big concern is that arrow functions aren't just regular functions of the different syntax, they behave differently in a number of important ways and that will introduce problems.

  34. Nicholas C. Zakas

    @David - My only rule about feature detection is don't use eval(). :) Especially if you're using JSHint or something to flag the use of eval() as unacceptable in your code, it makes it impossible to distinguish legitimate uses from ones that should be avoided.

    The other significant change to ECMAScript 5 was allowing reserved words to be used as object members.

  35. Nicholas C. Zakas

    @Andreas - I could see an argument for putting the methods on a string prototype. I would be equally happy either way.

  36. Nicholas C. Zakas

    @Jakub - Quasis are supposed to solve the string formatting problem. There is still no solution for the date formatting problem (though there is an ECMAScript internationalization API underdevelopment separately).

  37. Scott

    Amazing isn't it?

    The people who are working at correcting JavaScript, a language that is a subset of Java,
    do not know enough about Java and Java syntax to precisely and properly correct the
    errors that are found in JavaScript.

    Does ECMAScript 6 correct the class issues of the past? You know, the one where a method
    within the class resides outside the class and therefore you don't have a legitimate object oriented
    syntax.

    In regards to fat arrow functions, I doubt that I will ever use them. That is way too obfuscated.
    And we all know what happens when you need to make changes in code and you come across
    syntax you never seen before that has been obfuscated in such a way. You sit staring at it for
    several minutes, scanning back and forth in the code thinking; "what does.that do?"

    I guess I'll start looking for a JavaScript replacement, or just not use it anymore.

  38. Scott

    Or at least, not use it outside of basic AJAX functionality.

  39. Andreas Goebel

    @Scott: Mr. Crockford will hunt you down for "a language that is a subset of Java". Stop insulting ECMAscript please.

  40. Nicu

    I agree with everything said in this article. The new syntax puts me off and I've been writing Javascript since 2006.

    One approach I would use for the binding of "this" is inspired by Ruby blocks. If you add an ampersand (JS could choose a different character for all I care) before the last argument in a function definition, then the value of self* will be passed to that argument. And it's presence is completely optional, since you might not use it in the function. The character is only used in the function definition, in the block of the function you use "self" normally

    * by "self" I mean the reference to the current class/scope.

    Example:

    function SomeClass() {
    }

    SomeClass.prototype.log = function(text) {
    // implementation
    }

    SomeClass.prototype.onClickHandler = function(this, event, &self) {
    // "this" will point to the clicked element
    // "self" will point to the "SomeClass" instance
    self.log('You clicked: ', this);
    }

  41. Nicu

    I forgot to mention that you can pass the reference forward by using the "&" as well.

    function someFunction(arg1, arg2, &self) {
    callOtherFunction(arg1, &self);
    }

  42. Nicholas C. Zakas

    @Nicu - I'm not a fan of magic characters like that.

  43. ChadF

    Being somewhat of a general programming language purist myself I think the syntax of any language (once it has gone past it's infancy stage) should only change once in a blue moon (if that). I've seen too many of them throwing in all this syntactic sugar junk far more than seems needed. Why, because someone doesn't want to type a few extra characters here and there? I suppose they are bowing to the large number of developers that seem to _need_ an IDE to do 80% of the work for them, and even that 20% left is so much effort. I'm reminded of that old Jetsons episode where George had to work those excruciating 5 hour work weeks (yes - 5 hours a whole week). Not to say that everyone using an IDE is a bad developer, but there are certainly those that use it as a crutch and would be lost if they had to use notepad/pico/vi.

    In the last few versions of Java it's been what seems like non-trivial syntax changes every time (ugg!). So now _everyone_ has to upgrade their compilers and run times if anyone in their code/library chain used syntax that breaks backwards compatibility. So the one that commented how EMCAScript is just following what Java 8 is doing (and M$/C#, ugg!) sounds like "If others jumped off a cliff, would you?"

    So in conclusion I think that language syntax specifications should change very rarely and only to make the language more powerful (in doing something _new_, not the same things in a slightly more convenient way) or to fix a problem (like code being very ambiguous and missing the syntax needed to make it clear). This also applies to run time libraries to a degree in that core APIs changing too often can lead to the same incompatibilities problem. At least missing libraries can sometimes be emulated with some drop-in components without replacing everything, but syntax often can't be emulated. And the thing with libraries changes is if the newer code doesn't replace something old and that new code isn't referenced then it shouldn't be incompatible.

    Also what about an alternative-alternative of:

    function getName() {
    return this.name;
    }

    as:

    function window.getName() {
    return this.name;
    }

    Ok, let me step down the ladder to get off this soap box and then everyone can throw their tomatoes at me. Make sure they are extra rotten! ;)

  44. Alex

    Those fat arrow functions look awful. Every time I see new stuff from the ECMAScript committee I have to wonder if they ever even used JS...

  45. Rick Waldron

    Every single comment making claims similar to this:

    "ECMAScript committee I have to wonder if they ever even used JS"

    Should give me a call: 857-540-9264 and say it to me directly. While it's ringing, I want you to also review this url: http://github.com/rwldrn and think about what you'll say to me.

    Keep in mind that I'm sitting in a room right now with this "ECMAScript committee"... ya know... not writing JS... So leave me a message if I don't answer.

  46. Nicholas C. Zakas

    @Rick - I think your comment is unfair for two reasons. First, most definitely not every comment says anything to that effect. Of the several dozen comments on this post, there are a handful that make such a claim (including the one right before yours).

    Second, you just joined TC-39 (was it a month ago?) and had no part in the design of these features. I think it is fair to say that those who came up with these features don't write JavaScript for a living (either server-side or client-side).

  47. Havvy

    Small anonymous functions...what languages have them?

    Scala, Clojure, Python, Ruby, Coffeescript, and more. The arrow is read 'goes to'. For example, x => x*x is read as 'x goes to x times x'. This is extremely useful for short functions. As for the optional parenthesis for the one-arg case, I'd say put them anyways. Consistency outweighs the two-letter gain.

    The quasiliterals should probably be done via functions though, but if you can define unique quasiliteral handlers, then you have a macro system. Otherwise, I don't see the point of it.

  48. zwetan

    @Nicholas -- very well put, thanks to have sum up the situation

    to be honest since ES4 failure I abandoned all hope for ECMAScript futur

    @Rick -- I waited 10 years for the ECMAScript committee to wake up and start to update the standard
    I waited 5 more years to see ES4 completely burn to the ground

    I can understand your reaction as I'm pretty sure you and others from committee do use JS extensively
    but that "design by committee" when it fails to listen to the mass of JS developers complaining is like
    saying to those dev "shut up bitches we know better"

    As a JS dev since the early hours I'm tired of this arrogant shit

    All those years of design by committee for what ?
    JS2 draft, ES4, ES-harmony, ES5, ES6, ES-next ...

    I tell you what, put this "fat arrow" feature to the vote on twitter, fb, g+, whatever
    and I can guarantee you a mayhem of angry JS dev voting against it

    but nooooo, ECMASCript committee will never do that, design by committee is too precious,
    let's never listen to the little guys that do use the language night and day

  49. Rick Waldron

    @Nicholas actually, I was heavily involved in lobbying FOR fat arrow. I also wrote the initial specs for the two new Array.of and Array.from constructors that are now in the ES6 draft.

    @zwetan sorry, but none of that is true, everyone is welcome to join the discussion that takes place on a public mailing list. All that is expected is that you're thoughtful of others and provide meaningful, informed and intelligent arguments (which is exactly how I got involved).

  50. Josh

    Nice thoughtful write up, Nicholas.

  51. yuriy zaytsev

    @zwetan so, i'm real js developer and I love fat arrow -- what does that changes?

    You don't like coffeescript, do you? Cleaner syntax is always better.

  52. Lea Verou

    What does "look like JavaScript" even mean? JavaScript, just like every language (including natural languages), is not a static creation. It evolves over time, and its trademark "look" will change too. The contrary would be bad, it would mean the language is stagnating. Imagine if the early adopters of JS were against object and array literals because they "didn’t look like JavaScript"? Indeed, back then, Array() and Object() looked a lot more like JavaScript.

  53. Julian Lloyd

    Thanks for sharing your thoughts on this, and definitely agree with you... hopefully some of these issues can be addressed in the near future.

  54. Niclas Norgren

    Spot on, Nicholas

  55. Stuart Wakefield

    ChadF I think you might be a genius...

    function [scope.]name () {...}

    Awesome! I personally love it, it makes a lot of sense. I know it is similar to what Nicholas suggested. From a Java perspective angled braces mean types to me so it is a bit confusing, whereas this is elegance...

    So I imagine that you should be able to do this to bind the function to bind the this value in the parent scope...

    function Person(name) {
    this.name = name;
    function this.introduceSelf() {
    alert("Hi, my name is " + this.name + "!");
    }
    }

    Or some special case where you bind it to the prototype it will, when an instance of the class is created, bind the this value of the instance's method to the instance.

    function Person.prototype.shoutOwnName() {
    alert(this.name.toUpperCase() + "!!!");
    }

    Or you could define functions that are bound to specific instances of objects or primitives

    var p1 = [0,1];

    function obj.getVector(p) {
    return [p[0] - this[0],p[1] - this[1]];
    }

    // Normal scoped call
    var p2 = obj.getVector([2,5]); // Should equal [2,4]

    // Alias function
    gv = obj.getVector;

    // Aliased call
    var p3 = gv([2,5]); // Should equal [2,4]

    var str = "Hello";

    function str.getVowels() {
    return this.replace(/[^aeiou]+/ig, "");
    }

    // Normal scoped call
    var vowels1 = str.getVowels(); // Should equal "eo"

    // Alias
    var gv = str.getVowels;

    // Aliased call
    var vowels2 = gv(); // Should equal "eo"

    As for the other things this new function notation is trying to solve, I'm not convinced... If function is too long to type, either start using an IDE that has code assist or, alternatively, open notepad and type the word function, copy and paste as needed... Tadaaaa! If it is truly functional syntax, as in functional programming, attempting to access "this" should result in an error as you are trying to use state in a stateless paradigm. There is a distinct lack of clarity as to what exactly the new function syntax is meant to solve.

  56. Pavel Filippov

    You're not alone on this. I found new syntax complex and misleading. But it's from someone with 10+ years spend looking on the old one, so I'm pretty biased.

  57. Nicolas Vandamme

    I don't like fat arrows, it seems alien to javascript and much more C# to me (delegates and lambda expressions).
    Why do they want to replace the logic behind .bind(), .apply(), .call() ?
    In other high level langs like python or ruby, you can either "bind" a function as method to a class / instance (types.MethodType() in python, .bind() in ruby) or binding another class / instance methods via specialized call (in python : by calling class method with first argument as scope or by using super() as a caller with class and scope as arguments).

    Maybe something like these syntaxes would be more appropriate :

    function () {} //as proposed
    function () < [scope] {} //ruby like
    function () with [scope] {} //python like

    As speaking of this, the named arguments and rest arguments draft are ugly. Why using '...arguments' instead of much more readable and powerful syntaxe like *args **kwargs in python ? For example :

    Actual proposal:

    function (arg1, arg2, kwarg1=default_value, kwarg2=default_value, ...arguments) {
    // arguments array contains other arguments passed on call without distinguishing named args
    }

    Python like proposal:

    function (arg1, arg2, kwarg1=default_value, kwarg2=default_value, *args, **kwargs) {
    // args is similar to rest arguments containing only non explicits simple arguments passed on call
    // kwargs is an object containing non explicits named arguments passed on call
    }

    For string formatting, i don't think the proposed syntax is clear. I'd prefer a .format() as proposed or a printf like syntax :

    '%s is %i and {test}'.format(name, content, {test:true}); // via String.format or String.prototype.format
    '%s is %i and {test}' % (name, content, {test:true}); // via special syntax %, python/ruby like

    For String and multiline context, trailing backslash is good way (note that an alternative like triple quoting might be good too: """ a multiline string """) but the real problem is that String is missing binary and litteral contexts. In python there are string identifiers like r'a string with \ and every symbols non interpreted, including unicode' or b'a string treated as binary blob and left as is'. One example is strings that are converted to regexp litterals : non regexp symbols must be backslash protected before RegExp initializing otherwise they will be used by the regexp parser.

    new RegExp("[\]]"); // throw a parse error because \] is already interpreted as ]

    With string litterrals as binary or raw string, it is not a problem anymore.

    Anyway great post, it's cool to have an overview about javascript future !

  58. Nicholas C. Zakas

    @Havvy - thanks for the insights on how to properly pronounce the arrow syntax. Again, one of my big problems with that syntax is that it's not simply a more compact syntax for functions. It fundamentally changes several things about how functions work, and that is confusing.

  59. Nicholas C. Zakas

    @Rick - I apologize if I implied that you didn't have any influence on ES6, that wasn't my intent. I know that you've been active on es-discuss for a while (I too, have lobbied for or against things). My point was that as a new member of the committee, you weren't responsible for the parts that I'm complaining about.

  60. Nicholas C. Zakas

    @Lea - All languages take on a particular look. French is very easy to distinguish from English. Greek is easy to distinguish from Japanese. JavaScript is easy to distinguish from Perl and Java. There is definitely a character to the syntax of a language that is hard to capture in words but is nonetheless obvious to people who look at it. The difference between object and array literals and arrow functions is that the former all have analogs without special syntax. You absolutely cannot re-create the type of function without using the fat arrow.

    As I said, I'm not against new syntax on principle, I just liked to blend in with the surroundings. There are parts of ES6 that very obviously blend quite nicely but there are also parts that stick out like a sore thumb.

  61. Nicholas C. Zakas

    @Nicolas - I actually like the syntax for rest arguments. I strongly dislike magical single characters like *. I don't like them because it's very easy to miss type a single character, thus changing the meaning of something. I always prefer using more than one character to indicate special cases because it limits the opportunity for error. Plus, this is the same way it works in Java, so it's not without precedent.

    I could go either way with formatting strings, I'm not religious about using the sprintf version vs. String.format() with name placeholders. I would be thrilled with either one being part of core JavaScript.

  62. Alex

    @Rick: Apologies, reading back my comment sounded a little disrespectful, and as zwetan pointed out it can often feel as if changes are being pushed down from "high above" with little input from the masses. This is false, of course, but as a long time JS developer it's hard not to get a little resistant to change.

    That being said, I am all for brevity, but brevity at the cost of clarity is a trade off I'm a little uncomfortable with. New syntax is great if it makes things clearer and/or removes boilerplate (one of the things arrow syntax appears to address), but this to me feels more like a change for the sake of change without fixing something that was "broken" to begin with.

    I'm also not sure how I feel about importing syntax sugar from other flavor of the month languages. Especially because JS has been around so long, the last thing I want is new syntax to do something that's already possible in JS (sure, it might be a bit more verbose). Developers new to JS already have a tough time wrapping their head around a functional language wrapped in C style syntax.. just my two cents.

  63. Matej

    It seems as someone want to change JS to another language. This language is specific and does not need so radical change. People hate changes. Work on language progress but not on radical inovation. It is bad for all who supports this language.

  64. Alex Russell

    Hey Nicholas:

    I'm going to try not to attribute the profundity of many of your commenters to you (although my Defense Against the Trolling Arts skills may have weakened), and I responded to Marco here: https://plus.google.com/103...

    What really gets me about your post is that there's a high bar in proposing alternatives (does it work in the grammar? is it still LR1? does it solve the use-cases and, hopefully, pay us back with even more power?) that none of your suggestions aspire to. Even when I agree with your concerns (and I do agree with a lot of them), there's very little here to give me hope that your advocacy around things you don't like is going to help me change minds on the committee.

    For instance, I like requiring curlies for all callable declarations, I wish we had soft lexical this binding (see: http://www.mail-archive.com... -- they wouldn't pwn .call(), .apply(), etc.), and I find string interpolation ugly (we *might* be able to use triple-quotes if we raise the issue now), but nothing in your list of suggestions is actually useful -- mostly thanks to your tautology-backed Conclusion.

    Being a "JS purist" and not liking new syntax because it's different from what we know/like means that, in effect, that your baseline scenario is that JS is OK the way it is. That's an incompatible viewpoint with the the needs of progress: for things to be better, they *must* be different.

    We won't break compat, so you're welcome to use what we've got now forever. But calling new stuff out because it's *new* says more about you than it does about the features under debate. For now, I'm taking your feedback with that in mind.

    Regards

  65. Rick Waldron

    I'd like to encourage everyone here that is feeling unsure or even unconvinced about the new language additions to try them out first. Devs at Google have implemented several* ES6 features in Traceur (http://traceur-compiler.goo... that can be "test-driven" online:



    // Filter an array of items
    var items = [ 1, 2, 3, 4 ].filter( x => x % 2 );

    // [ 1, 3 ]

    Go to example



    // Using [ ...spread ] to convert nodelist to an array and then iterate
    [ ...document.querySelectorAll("div") ].forEach( node => {
    console.log( node );
    });

    // HTMLDivElement
    // HTMLDivElement

    Go to example



    // make an array of objects with a node
    var nodes = document.querySelectorAll("div"),
    nodeObjs = [ ...nodes ].map( (node, k) => ({ index: k, n: node }) );

    console.log( nodeObjs );

    [
    {
    index: 0,
    n: HTMLDivElement
    },
    {
    index: 1,
    n: HTMLDivElement
    }
    ]

    Go to example

    I've put all of these in a gist if you'd like to fork and play around with them: https://gist.github.com/gis...

    *Supported by Traceur:

    blockBinding

    defaultParameters

    destructuring

    restParameters

    spread

    forOf

    propertyMethods

    classes

    These are just a few goodies :)

  66. Nicholas C. Zakas

    @Alex - Perhaps I misrepresented the purpose of this post. The purpose was to explain my opinion of the proposed syntax changes in ECMAScript 6. I threw in counter proposals for the things I didn't like as a comparison point because I knew people would ask, "well, what would you do instead?" The idea was to show that you can have new syntax that expresses the capability clearly as opposed to some of the real proposals which I find unclear. It was never my intent to say that the alternate this-binding syntax be taken forward to TC-39 (so yes, my suggestions don't aspire to the bar required). However, I don't see anything wrong with suggesting that string formatting and HTML escaping should be included as methods on strings. That's not new syntax, just new capabilities (and capabilities that already exist in JavaScript libraries).

    As far as quasis go, I still don't see how they can be used with the common way of externalizing strings into resource bundles or externalizing templates. They seem to only work when defined in the same context as the named substitutions they contain. That alone makes them mostly unusable in most circumstances. Perhaps the target audience for quasis is tool developers that can handle this sort of issue, but I don't see a good string formatting solution for regular developers here.

    You should also note that even though I said I'm a JavaScript purist, I also started this post with syntax changes that I like and when I like new syntax to be introduced. It seems like most readers, including yourself, skipped over that to get to the more controversial bits. I never, anywhere in this post, said that I didn't like the new syntax because it's new. I said that I didn't like some of the new syntax because it was unclear as to what was happening.

  67. Rob Brackett

    I definitely agree about quasis/string formatting—a much simpler JavaScript-like take on it without new syntax would be wonderful. You're probably already aware of the other String.format() proposal: http://wiki.ecmascript.org/...
    Although I'm not sure it's really going anywhere, since quasis are on the harmony accepted page and that String.format() proposal isn't.

    In any case, I wrote an implementation of it a while ago that you might find useful: https://github.com/Mr0grog/...

    The implementation isn't the prettiest thing in the world, but it pretty fully implements what I think is a really nice and straightforward API.

  68. Nicholas C. Zakas

    @Rob - yes, I mentioned that proposal in the post. Thanks for sharing your implementation.

  69. Isaac Z. Schlueter

    A way to clearly create callbacks with a lexically-bound "this" is something that is desperately needed. I was strongly in the "just use .bind()" camp, until I realized that I didn't *actually* do this in my programs. Since then, I started actually using bind, so that I could put my money where my mouth is, so to speak.

    fs.readFile(someFile, function(er, data) {
    if (er) return this.emit('error', er);
    this.doStuffWithData(data);
    }.bind(this));

    It's really just trash. It puts the "this" value at the *bottom* of the block, when you really need it at the *top* in order to properly read the flow of execution. An alternative is to use named functions and rely on hoisting:

    fs.readFile(someFile, then.bind(this));
    function then(er, data) {
    if (er) return this.emit('error', er);
    this.doStuffWithData(data);
    }

    This is a little bit nicer, but still feels clumsy. It's not clear that "then" is a single-use function, and it's a lot of ceremony if you're only going to use it once. What we really need is a way to say: just keep 'this' bound the way that it is already. It should be visually distinctive *at the start* of the block rather than the end, and for all its potential for abuse, arrow lambdas provide that:

    fs.readFile(someFile, (er, data) => {
    if (er) return this.emit('error', er);
    this.doStuffWithData(data);
    });

    I still use `.bind(this)` in my programs, most of the time. I find it's still a bit nicer than setting a "self" or "me" var and remembering to use that instead of "this", since I usually end up slipping up and typing "this" to refer to the current object, and I have a hard time realizing that I used "this" to mean "this" when I should have typed "me".

    The other potential nice thing about => functions is that the interpreter *knows* up front that the function cannot ever be used as a constructor or bound to any other object, so it can be more aggressive in its optimizations.

    The value of immediate return becomes more obvious when you do a lot of map/filter/reduce type operations on arrays. I find myself typing this sort of stuff a lot:

    var topTen = Object.keys(data).map(function(k) {
    return [k, data[k]];
    }).filter(function (kv) {
    return kv[0] && kv[1];
    }).sort(function(a, b) {
    return a[1].value > b[1].value ? -1 : 1
    }).slice(0, 10).reduce(function(set, kv) {
    set[kv[0]] = kv[1];
    return set;
    }, {});

    With immediate returns, that becomes:

    var topTen = Object.keys(data)
    .map((k) => [k, data[k]])
    .filter((kv) => kv[0] && kv[1])
    .sort((a, b) => a[1].value > b[1].value ? -1 : 1)
    .slice(0, 10)
    .reduce((set, kv) => {
    set[kv[0]] = kv[1];
    return set
    }, {});

    There's a reason why functional languages tend to favor this kind of syntax; when you're writing a lot of small functions, it's easier if the syntax is smaller as well.

    Quasis address some valid use-cases, but I do share some of your skepticism, and I'm not (yet?) convinced that they're the best approach for doing multi-line strings. I *do* long for multi-line strings, though. When there's a language feature that bash and php do much more elegantly, then something is very wrong ;) Python's triple-quote is basically perfect, imo. In a perfect world, this would be valid:

    assert("""
    this string
    spans
    multiple lines
    """ === "this string\nspans\nmultiple lines");

    Yes, you can do this (and I do):

    "this string\n" +
    "spans\n" +
    "multiple lines"

    but it's clunky, and there's a lot of extra characters that make reading a bit harder.

  70. Rob Brackett

    @Nicholas Ah, so you did! I completely missed it.

  71. Nicolas Vandamme

    @Nicholas I understand that *args and **kwargs feel alien, but it is not about special chars '*' but about distinguishing simple arguments from named arguments. Basically any identifiers would be good. For example :

    function (arg1, named_arg1 = some_value, ...rest, :::named_rest) or function (arg1, named_arg1 = some_value, [args], {named_args})

  72. Nicolas Vandamme

    Sorry about the second example, correction :

    function (arg1, named_arg1 = some_value, [[args]], {{named_args}})

  73. Daniel Mascena

    Thank you to bring this discussion to the table.. completely agree with you on the new syntax. We need to stand up for the good of JavaScript, adding (confusing) syntatic sugar to make JS looks like Python don't make don't resolves the issues of the language and (maybe) will take apart the community. Please, keep JS simple, but more efficient!!!! There is already a abstraction to provide this kind of syntatic sugar (CoffeeScript) for the Ruby/Python lovers, don't mess with JavaScript.

  74. Rhys

    I'm not a fan of new syntactic sugar for the sake of typing in less characters. The fact is you don't have to put it in the language and force others to learn it. Just setup your IDE so when you type -> it changes to "function". I'm sure you can do something similar with => which could put a bind(function() {}, this) around your code as well.

    Or just use coffeescript.

  75. Nicholas C. Zakas

    @Isaac - Thanks for the great insights on this. As I said in the post, I do agree that there needs to be an easier way to set the value of this and I also agree that difference should be at the beginning of the function and not at the end. I further agree that the arrow syntax makes a lot of sense when you're doing a bunch of map and reduce stuff. My main issue is that arrow functions have so many side effects. If it was just a more terse version of a regular function, I'd feel a little bit better. I just really wish there was a nicer way to bind this for functions that you do intend to use frequently.

  76. David Chambers

    For those who can't wait for ES6 to standardize string formatting, there's String::format:

    // before
    repo.owner + "/" + repo.slug + " has " + repo.followers.length + " followers"

    // after
    "{owner}/{slug} has {followers.length} followers".format(repo)

  77. Carl

    @Rhys: It is not only about typing less, but also reading less. So proposing to let an IDE replace the terse syntax with a verbose one is really no solution.

  78. Carl

    Beside that: Every terse syntax means less parsing. Let the complex semantics be in the internal machine and keep it away from the code text.

  79. Schalk Neethling

    Thank you, thank you for writing this. You simply and concisely echoed my thoughts.

  80. Mike Wilcox

    Nicholas, I don't always agree with you, but I do here, 100%. I think it's pertinent that most commenters do too.

    While a bit overly general, I think a good rule of thumb should be if it can't be shimmed, it should be reconsidered. Function.bind is incredibly useful and can be shimmed. Fat arrow and quasis cannot. Think getters and setters - yes we really wanted and needed them, but I don't think the syntax was carefully considered and we still can't use them until when? 2016 maybe? Hard to get excited about features like that.

  81. James Manning

    Random metric for judging new features: is there a source transformation you could apply such that it would run the same in the previous version?

  82. Isaac Rivera

    Has a PHP mob taken over ECMAScript?

  83. James Manning

    While I understand it's not really a good idea (at least long term), part of me kind of hopes the Traceur approach is how all runtimes end up supporting ECMAScript 6. Admittedly, this is because I'm hoping that developing/debugging through SourceMaps becomes common enough to help drive improving the tooling across the ecosystem, helping out users of alternative languages like CoffeeScript. :)

    http://www.html5rocks.com/e...

  84. orustam

    I fully agree with you. I think the problem is that people are coming to JavaScript with Python expirience and trying to bring Python features to JavaScript to have some kind of "SOFT TRANSITION". i fear that some day the language (JavaScript) i hated once and love today will just disappear and everything taht will be left will be some sort of new language, similiar to python or ruby or any other "fancy" language. they just don't understand the full beauty of Javascript Functions. By the way this "fat arrow" notation and other stuff like "quasis" etc. are pretty similliar to "DART" syntax. I think Google couldn't push their own new language and now they trying to convert "Javascript" to "DART" to make transition less painfull. Simplicity is the way to success, that's why "jQuery succed" (nothing against YUI) :) .

  85. Adam R

    Yawn. I've been using lambda expressions in C# for years. The syntax is about identical, and is quite addicting once you spend the 5 minutes needed to get used to it.

    This is why I hate purists. I can't wait for this feature.

  86. Anton Suprun

    > I know I’m probably alone on this, but I don’t think the syntax is clear.

    You are not alone. I'm just waiting for all these fat functions and other nonsense to make those hipster javascripters' live miserable and end up being an error in jslinters.

  87. Nicholas C. Zakas

    @Adam - You, like several other commenters, seem to have missed the fact that even though I'm a purist, I am absolutely open to new syntax when it makes sense. You'll also note that my biggest concern about the arrow functions was the number of side effects that it had. It's not simply a shorter syntax for functions, it fundamentally changes how those functions work, and I think that is confusing.

  88. Adam R

    Well I'm almost done with your High Performance JavaScript book, so it's clear that you're brilliant beyond description. Seriously.

    For me though, as someone who writes lots, and lots of object-oriented JS everyday (no, seriously, every...day) the fat arrow couldn't have come soon enough.

    Yes, `this` is static to what `this` is in the enclosing block. That's by design so I don't have to sprinkle my code with .bind(this) all the time (or do the ever cheesy var self = this)

    I didn't know these functions lacked a prototype, but why would they need one? These functions are meant to be used as a simple callback, not a constructor.

    Overall the rules about the functions needing or not needing braces, needing parentheses for multiple parameters, but not needing them for one parameter, and needing them for zero parameters might seem confusing, but come on, if .NET developers can figure this out, surely JS developers can.

    And finally, this might very well confuse some newbie developers, but so what? There's already mountains of awful JS written every day, and it'll just be more opportunities for you to consult :-)

  89. Heinrich Göbl

    I agree with the article.
    Probably ES6 will be doomed like ES4 ...

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.