What is the meaning of this?

By YUI TeamMarch 30th, 2012

JavaScript is an amalgam of good parts and bad parts. Its best parts came from Self (prototypes) and Scheme (lexically scoped nested functions). But the interaction of those two very good parts produced some bad parts.

When a function is called with the function invocation pattern, its this is not bound to the outer function’s this as we would hope, but is instead bound to the global object, which is horrible. (ES5/strict binds the inner function’s this to undefined, which is much less wrong than binding the global object, but is still not right.) The workarounds for this include the use of bind functions and riddles like

var that = this;

Most functions are not intended to be used as constructors, yet every function has a prototype object just in case it turns out to be one of the rare functions that is a constructor. This is an obvious source of inefficiency.

Function objects are mutable like other objects. This will make the securing of JavaScript more difficult because every function object can be used as a channel to facilitate unwanted collusion between widgets. ES5 provides tools to freeze functions, making them immutable, but the tools are really difficult to use for that purpose.

The Sixth Edition of ECMAScript may correct all of these problems.

The Sixth Edition is still being debated and drafted. We won’t know for certain what will be in the next edition until it is approved by the ECMA General Assembly, a milestone that will not occur this year. It is impossible to speak with certainty about future editions. The following prediction is based on my understanding of current developments, but it could ultimately prove to be wrong in every detail.

The next edition may have a more compact alternative to the function operator: the => operator. It takes a parameter list on the left, and on the right it takes either a function body wrapped in braces, or an expression. If the thing on the right is an expression, then a function body that returns the value of the expression is made for you. So instead of writing

function (x) {
    return x * x;
}

you can instead write

(x) => x * x

Functions written in this new fat arrow form always use the this of the outer function, even when invoked as a method. That means that it is no longer necessary to use bind or resort to that tricks.

If you want a method that receives a dynamic binding to the method’s object, then you must include this as the first pseudo parameter.

(this, x) => {
    this.property = x;
}

This gives us a way to easily distinguish functions from methods. Functions use the outer function’s this, and methods explicitly name this in their parameters. Using the function invocation form on a method throws a type error.

Fat arrow functions do not have prototype properties, which makes them cheaper to make. They are immutable.

I am looking forward to using these new functions. They are lighter in appearance and implementation, and they correct a lot of the problems of conventional functions. As aways, there are tradeoffs. Adding new kinds of functions makes living with the language more complicated. The language will be a little more difficult to talk about.

If you are creating a simple factory function, you cannot put an object literal on the right of the => because a brace will be interpreted as a function body. So instead you must write either

() => ({}) // wrap the object literal in parens

or

() => {
    return {};
// wrap the object literal in a function body
}

Fortunately, JSLint will be able detect these sorts of ambiguities.

I am looking forward to using the new functions. But there is still a role for the old style functions. The new functions do not have names, so you will need to use the old functions to write self-recursive functions. You need the old functions for constructors, although I don’t recommend use of constructors. You will need the old functions to make mutable functions, although I don’t recommend those either. You will need the old functions if you want access to arguments, which you shouldn’t because we will have a new ... operator. And you will need the old functions to make generators that use the new yield operator.

31 Comments

  1. Aren’t you confusing the two function patterns there at the end? If I understand right, a fat arrow object factory ought to look like
    () => ({}),
    not
    function () => ({}).

  2. And so the confusion begins. Right you are.

  3. I am looking forward to using the new functions. But there is still a role for the old style functions

  4. Tomislav Sheshek said:
    March 31, 2012 at 12:06 am

    Interesting article!

    Can you give more details about the following:

    You need the old functions for constructors, although I don’t recommend use of constructors.

    What exactly are the drawbacks of using constructors?

  5. When it comes to declaring functions, I’d love to see JavaScript confess its mistakes, fix the problem by making functions use the “this” from the scope in which they were declared, and break backwards compatibility. Heresy, I know. But I don’t think it would be any rougher on JavaScript devs than introducing “methods”.

    I’ve always admired Python for having the foresight to break backwards compatibility in from Python 2 to 3. Tools like 2to3 can help to ease the transition, and similar tools could be written for JavaScript. Ultimately, if we’re going to be using JavaScript for many years it’s worth a few years of pain up front to admit the mistakes and get them right.

  6. The problem is not the conjunction of Self and Scheme. The problem is that the conjunction was designed horribly. If Scheme’s procedures had simply been introduced without a “this” then Javascript would have been much better off (plus or minus a few dozen other bad decisions…)

    Many good class and prototype object systems have been implemented in Scheme. Many of those had been implemented in the reknowned “short amount of time” the designer had to complete Javascript.

    None that I know of have been so awful as Javascript’s. None.

  7. It has been simplified again: http://wiki.ecmascript.org/doku.php?id=strawman:arrow_function_syntax

    Methods (dynamic this) are now handled by object literals (which have a shorter method notation) and (possibly) class declarations.

  8. What good is a method that can’t be named and called?

    Also, how do you refer to the return of the expression? Can you do like this?:

    var x = (y,z) => {z-y}

  9. “The new functions do not have names, so you will need to use the old functions to write self-recursive functions. You need the old functions for constructors, although I don’t recommend use of constructors. You will need the old functions to make mutable functions, although I don’t recommend those either. You will need the old functions if you want access to arguments, which you shouldn’t because we will have a new … operator. And you will need the old functions to make generators that use the new yield operator.”….

    Let’s just keep the “old functions” then! I don’t see any good enough reasons to why we would want to change the syntax so dramatically… oh! maybe Coffeescript is a reason, but still not good enough!

  10. This looks a whole lot like coffeescript syntax. Which is good, because the coffeescript docs are mighty thin.

  11. Actually, the agreement at the meeting does not include the optional this parameter. EG:


    (this,x)=>this.property=x

    is not allowed. Still need to use a function expression for that case.

    See the proposal.

  12. Hi Doug, this is really interesting but I’m finding the examples above hard to follow. You don’t define what the difference between a method and a function is, and you don’t show how (x) is called. Maybe you could use some concrete examples.

  13. You don’t need names for functions to be self-referential ly recursive if you have the y combinator.

  14. How about “use strict”; or “use ecma”;

  15. Hi Doug, one small correction: arrow functions are not immutable. I had a #-prefix (also usable with object and array literals to make “records” and “tuples”) in the original arrow strawman, but cut it to reach consensus.

    /be

  16. Why can’t generators use lambdas? What would go wrong with using “yield” in a lambda? (Other than “the language definition proscribes it”.)

  17. Also, how long before someone writes the obvious Y combinator so that you can write y((recurse, x) => { … })

  18. Michael Dudley said:
    March 31, 2012 at 2:39 pm

    This is like the lambda operator in C#, right? http://msdn.microsoft.com/en-us/library/bb397687.aspx

  19. @Mike & Doug — that was as beautiful as it was hilarious :D

    Doug – thanks for the writeup. I’m a big fan of yours and always enjoy your tutelage. Thanks for your commitment to the community!

  20. It is sad that we need to use the => syntax because there isn’t a nice word that could be used instead (e.g. method, def, etc). IMO JS will become quite cryptic and inaccessible to new comers with this syntax.

  21. Also, the optional leading (this) parameter idea met with resistance in the meeting, and I cut it too.

    Perhaps it should go back (but not the -> shorthand for (this)=>). I could use your support on es-discuss — look for the “arrow function syntax simplified” thread, my reply to Quildreen Motta.

    /be

  22. Douglas, when is this new version released?

    I use JS extensively since ’06, and Python since ’09, and can’t wait to see this in JS. I had a few things I wanted to try, but in Python they’d not have been portable, and in JS they’re just painful to write.

  23. Please, let’s use a word like ‘method’ rather than introducing more operators with precedence rules to remember.

    var foo = method (x) { … } works for me.

  24. I don’t understand why the yield operator won’t be supported by those new functions. Both features are new and, as far as I know, not incompatible.

    This bother me because this would be the only case I’d need the old functions.

  25. Ruben Oliveira said:
    May 3, 2012 at 2:10 am

    How will inheritance work?

  26. Will ECMAScript 6 offer full Class encapsulation from global variable leakage? This could save a ton of lost hours tracking down where someone simply forgot the “var” keyword!

  27. [...] 6th edition might bring us fat arrow notation – Douglas Crockford on fat arrows function (x) { return x * x; }   // becomes   (x) => x * [...]

  28. Rather sad JavaScript is going the “cryptic syntax” way of CoffeeCreep.

    Truly see the following more explicit and easier to type:

    var foo = method (x) { … }

    (as mentioned) or

    var foo = lambda (x) { … }

    I am glad to see PEP 20 thinking seeping into psyche of JavaScript coders. https://plus.google.com/115133653231679625609/posts/QNPFV5xEH1i Said that seeping does not happen soon enough, as otherwise JS will turn into syntactic soup.

  29. Erik Reppen said:
    July 13, 2012 at 3:57 pm

    I feel it should be pointed out: ‘this’ never refers to a function. Only an object. You could use arguments.callee to get a wrapping function reference but that’s deprecated and on its way out too. Calling a general function inside an object does evaluate this as the window object however, and yes, it is awful. The ‘this’ keyword is really only useful if a function is referenced as a property of an object (a method) or you bind, call, or apply a function to an object context.

    I believe JS2 has been envisioned as backwards compatibility breaking but the big scary problem is when we’re willing to break it and who really gets to call the shots on the redesign. That already unhinged the first effort at JS2.

  30. [...] YUI Blog had an interesting discussion of the meaning of “this” when scope is added. I had to read it twice to get it. I still [...]

  31. [...] is bound to the “this” of the outer function. Douglas Crockford has a great write up covering all of [...]