0

I'm new to arrow functions and I don't understand why I can use this code:

const adder = {
    sum: 0,
    add(numbers) {
        numbers.forEach(n => {
            this.sum += n;
        });
    }
};

adder.add([1,2,3]);
// adder.sum === 6

... and it works just fine, but in the following case the this is not bound properly:

const adder = {
    sum: 0,
    add: (numbers) => {
        numbers.forEach(n => {
            this.sum += n;
        });
    }
};

adder.add([1,2,3]);
// Cannot read property sum
Dávid Molnár
  • 7,524
  • 6
  • 25
  • 43

2 Answers2

3

From MDN:

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target.(...)

Meaning that inside an arrow function the this refers to the outter most this there is. If you run that in the browser, the this is the window object.

use adder.sum instead of this.sum.

Fiddle

pedromss
  • 2,170
  • 15
  • 22
  • Sorry, but I don't understand. So, in the first case `this.sum` refers to `adder.sum` and the second case `window.sum`? Why is there a difference between the two? You say it's the outer most `this`, but that means the two cases should be identical. – Dávid Molnár Aug 21 '17 at 07:47
  • They are. An arrow function does not bind to any `this`. So when you access `this.adder` you are accessing the first `this` that is in context, probably the `window` object. – pedromss Aug 21 '17 at 07:59
1

Arrow function allows to reach lexical this. Which is a context where adder is defined, not adder itself.

It is expected to work like that:

function Foo () {
    // this === foo;
    this.sum = 0;

    const adder = {
        sum: 0,
        add: (numbers) => {
            numbers.forEach(n => {
                // this === foo;
                this.sum += n;
            });
        }
    };

    adder.add([1,2,3]);
}

const foo = new Foo;

And

const adder = {
    sum: 0,
    add(numbers) { ... }
};

is a shortcut for

const adder = {
    sum: 0,
    add: function (numbers) { ... }
};

so add method will have adder as this when it's called like adder.add(...).

Estus Flask
  • 150,909
  • 47
  • 291
  • 441
  • Of course, here `adder.add` is never called and not available to the outside either. – Bergi Aug 20 '17 at 17:54
  • Thanks, I fixed it for clarity. – Estus Flask Aug 20 '17 at 17:56
  • Sorry, I don't understand. How come, that in the first case `this.sum` refers to `adder.sum` or is that a false assumption? – Dávid Molnár Aug 21 '17 at 07:50
  • @DávidMolnár In the first case `add` is regular function, which gets dynamic `this`, depending on how it's called. When it's called like `adder.add(...)`, it gets `adder` as `this` because this is the object method were called on. This is how regular functions differ from arrows (explained in dupe questions). – Estus Flask Aug 21 '17 at 08:24
  • Thanks for the comparison examples, most useful! – MarsAndBack Jan 01 '20 at 00:34