0

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.

Jeremy
  • 1
  • 85
  • 340
  • 366
Amit Erandole
  • 11,995
  • 23
  • 65
  • 103

2 Answers2

2

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
Saad
  • 49,729
  • 21
  • 73
  • 112
  • Here can be shorter implementation of `concatAll`: `return this.reduce((res, subArr) => [...res, ...subArr], [])` – just-boris Nov 30 '15 at 18:18
0

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
}
simonzack
  • 19,729
  • 13
  • 73
  • 118