Amit Erandole
Amit Erandole

Reputation: 12271

Why does the es6 version of my function say "Cannot read property 'forEach' of undefined"

This version of my es6 function doesn't work:

Array.prototype.concatAll = () => {
  let results = [];

  this.forEach((subArray) => {
    subArray.forEach((item) => {
      results.push(item);
    });
  });

  return results;
};

When I use it like this:

var stocks = exchanges.concatAll();

The console says: Cannot read property 'forEach' of undefined

However this es5 version works just fine:

Array.prototype.concatAll = function() {
  let results = [];

  this.forEach((subArray) => {
    subArray.forEach((item) => {
      results.push(item);
    });
  });

  return results;
};

Why is this? What exactly is happening with this inside the es6 version? I would like to understand.

Upvotes: 0

Views: 318

Answers (2)

Saad
Saad

Reputation: 53829

This has already been mentioned, but this isn't a good use-case for arrow functions due to the fact that they bind the value of this. Another way you can do this with ES6 is to use Object.assign.

For your example:

Object.assign(Array.prototype, {
  concatAll() {
    let results = [];

    this.forEach(subArr => {
      subArr.forEach(item => {
        results.push(item);
      });
    });

    return results;
  }
});

And then you could just use the code like this:

let arr = [
  [1, 2, 3],
  [4, 5, 6]
];

console.log(arr.concatAll()); // -> [1, 2, 3, 4, 5, 6]

You can also add on multiple methods like this:

Object.assign(Array.prototype, {
  sum() {
    return this.reduce((a, b) => a + b);
  },

  max() {
    return this.reduce((a, b) => (a > b) ? a : b);
  },

  min() {
    return this.reduce((a, b) => (a < b) ? a : b);
  }
});

let arr = [1, 2, 3];

console.log(arr.sum()); // -> 6
console.log(arr.max()); // -> 3
console.log(arr.min()); // -> 1

Upvotes: 1

simonzack
simonzack

Reputation: 20928

The arrow function's scope of this is it's parent scope. So in this case this is undefined. So in this case you would still need a function.

Check the start of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions.

An arrow function expression (also known as fat arrow function) has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.

ES6 can still simplify your code though by using for of:

Array.prototype.concatAll = function(){
  let results = []
  for(let subArray of this)
    for(let item of subArray)
      results.push(item)
  return results
}

Upvotes: 0

Related Questions