Monday, July 16, 2012

Arrow Functions

First post: Arrow Functions
Since this is the first post on the new blog, I had to find something interesting to blog about. As I went through the current ES.Next strawman docs and the current ES6 Spec doc, I decided that Arrow Functions would be a good place to start. As I look at all of the features proposed in the Spec, I think that Arrow Functions will be one of the first pieces that people begin to implement.

DISCLAIMER
Please keep in mind that based on the specification, this code will work as I have described it, with minimal-to-no variance among the browser vendors. I would feel a lot more confident if I could test the code before publishing this post. Since I can't test it first, I can either 1) not post this or 2) post it with my best assumptions based on the docs. I am choosing the later.

Reading Material
Anyone looking for some good reading material on the subject, see here:
Example
Unfortunately none of the browser vendors have implemented this piece of ES6 yet, despite it being officially drafted into ES6. Additionally, none of the up-to-date transpilers and poly-fills support it either. Thus, I cannot give you any proven code, as I have no environments, transpilers or poly-fills that support the syntax. So, the provided code will be based on the definition the current official ES6 spec. 

Here is a the basic syntax:

let sq = x => x * x ;

Here we have an Arrow Function Expression. This is an expression that declares a new Arrow Function. In this case, we end up with a function named 'sq'. 'sq' takes one parameter, which is multiplied by itself and then returned.

Parameters (to the left of the arrow =>)
Our 'sq' function takes one parameter, defined by 'x'. Notice 'x' was not wrapped with parens. If your arrow function takes more than one param, the parens will be required. It would look similar to 'let mult = (x, y) => x * y;'

Method Body (to the right of the arrow =>)
Our 'sq' method body has only one line of code. Like 'if' or 'for' statements, we don't need to wrap our method body in braces {} when it only consists of one line. If our method body has more than one line of code, you will need to wrap it with braces. Additionally, notice that I omitted the word 'return' from the code. With one line method bodies, the resulting value is implicitly returned. No 'return' required for one line method bodies. When your method body is more then one line, you will need to explicitly provide a return statement.

Another Example
Let's see another Arrow Function Expression:

var a = {
    name: 'THING-A',
    whoami : function(){
        console.log("I AM THIS",this.name);
    }
};
var b = {
    name: 'THING-B',
    whoami : () => {console.log("I AM THIS",this.name)}
};
a.whoami(); //I AM THIS THING-A
b.whoami(); //I AM THIS THING-B
a.whoami.call(b); //I AM THIS THING-B
b.whoami.call(a); //I AM THIS THING-B ???


Here we have two objects, 'a' and 'b'. 'a' has a 'whoami' function that is a traditional function expression. 'b' has a 'whoami' function that is an arrow function expression. While they appear to be the same, they will behave differently with regard to 'this'. 'a' allows me to reassign 'this' by using 'a.whoami.call' and passing a new scope (b) as the first parameter. However, 'b.whoami.call' doesn't allow for scope reassignment because it is an arrow function. So when you call 'b.whoami.call' and pass a new scope, the new scope is ignored. Arrow Functions are lexically bound to the 'this' of where it is declared. In other words, when an Arrow Function is declared, whatever the scope is at that time, that is 'this'.

The way that Arrow Function relate to their 'this' has a lot of implications. Too many to talk about here. I will cover all of this in the book (once O'Reilly gets the link up for pre-order and e-copies, I will get the link here).

Why add Arrow Functions?
Why add this? We already understood what was going on... so why change it? I think that Brendan Eich has provided a great list of reasons ('Rationale' section):

  • Hard to beat C# and CoffeeScript here (we want the unparenthesized single-parameter form as in C#).
    • TC39 should embrace, clean-up, and extend rather than re-invent or compete with de-facto and nearby de-jure standards.
    • However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun.
    • Currently we don’t make () or {} in () => {} optional, but we could at risk of losing consensus (but no grammatical bugs bite optionality here).
  • Lexical this matches the dominant cohort measured by Kevin Smith (see the BTF Measurements thread) that either does not use this or wants it lexically bound.
    • Best results after modifying subject code to use method definition shorthand and only then scanning for function.
    • From lexical this it follows that arrow functions are not constructors (no .prototype or [[Construct]]).
  • => parses as if it were a low-precedence (assignment) operator joining a restricted comma expression (implicitly quoted) to a body.
    • This avoids precedence inversion when the body is an AssignmentExpression.
    • No preference for object literal over block (see block vs object literal to keep grammar simple and match expression-statement.
  • TCP compliance “above” expressions – for statements and programs – looks like a mismatch with JS functions, old-style or arrow.
    • return is problematic because users want to write early returns in async callbacks, which under TCP would throw.
    • break and continue in sync callbacks could work well but would reify as exceptions and be observable via finally even if uncatchable.
    • In general the statements vs. expressions rift in JS, inherited via Java from C, means full TCP creates inevitable confusion and bugs.


Eventually they want to add the ability to soft-bind to 'this' so that we have a dynamic-this opt-in option.

As is, I can't wait to get my hands on Arrow Functions! I can't wait to never have to write the following again!
var me = this;

No comments:

Post a Comment