Search code examples
javascriptecmascript-harmonyarrow-functions

Why does returning this ECMAScript Harmony arrow function expression produce unexpected behavior?


I've been playing with the new ECMAScript 6 features and this question has to do with arrow functions. The following code is a simple functional composition method assigned to the Function object's prototype. It works perfectly well using a simple anonymous function but does not when using an arrow function instead.

Function.prototype.compose = function (bar) {
    var foo = this;
    return function () {
        return foo(bar.apply(null, arguments));
    };
};

var addFive = function (baz) {
    return baz + 5;
};

var addTen = function (hello) {
    return hello + 10;
};

var addFifteen = addFive.compose(addTen);

console.log(addFifteen(10));

http://jsfiddle.net/oegonbmn/

Function.prototype.compose = function (bar) {
    var foo = this;
    return () => foo(bar.apply(null, arguments));
};

var addFive = function (baz) {
    return baz + 5;
};

var addTen = function (hello) {
    return hello + 10;
};

var addFifteen = addFive.compose(addTen);

console.log(addFifteen(10));

http://www.es6fiddle.com/hyo32b2p/

The first one logs 25 correctly to the console whereas the second one logs function (hello) { return hello + 10; }105 which doesn't exactly tell me what I'm doing wrong.

I am not returning the value within the arrow function since it is supposed to implicitly return the very last statement (the first and last in this instance) and I suppose the issue at hand has something to do with the lexical scoping and the values of this, maybe. Can anyone explain?


Solution

  • Both this and arguments are not (re)bound in arrow functions, but instead lexically scoped. That is, you get whatever they are bound to in the surrounding scope.

    In ES6, using arguments is deprecated anyway. The preferred solution is to use rest parameters:

    Function.prototype.compose = function (bar) {
      return (...args) => this(bar.apply(null, args));
    };
    

    or, in fact:

    Function.prototype.compose = function (bar) {
      return (...args) => this(bar(...args));
    };