1

I know this sounds like a opinion question, but I'm a Junior in JavaScript skills and would like to understand the technical plusses and minuses of each of the following ways of getting a this into a function (that has its own this, of course).

Let's say I write - and this is a real life example of mine -

Calculator.prototype.Initialize = function () {
    // Fill in all regions in the RegionsChecked array
    this.Data.forEach(function(region){
        this.RegionsChecked.push(region.RegionName);
    });
    …

and I realize that

"Oops, the this in this.RegionsChecked is supposed to actually refer to the Calculator function that is calling the Intialize function."

I either solve this problem by doing

var that = this;
this.Data.forEach(function(region){
    that.RegionsChecked.push(region.RegionName);
});

or

(function(calc){
    this.Data.forEach(function(region){
        calc.RegionsChecked.push(region.RegionName);
    });
})(this);

and I'm wondering which would be considered better or if there is an even better way (and why).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
user5648283
  • 5,913
  • 4
  • 22
  • 32
  • 1
    For the generic discussion, see [How to access the correct `this` / context inside a callback?](http://stackoverflow.com/q/20279484/1048572) – Bergi Dec 20 '15 at 13:07

2 Answers2

5

Array.prototype.forEach also takes a second argument that specifies the this value (context) with which the callback should be invoked.

this.data.forEach(function (region) {
  this.regionsChecked.push(region.regionName);
}, this);

A better alternative would be to use ES6 arrow functions, that are bound to the lexical this value:

this.data.forEach(region => {
  this.regionsChecked.push(region.regionName);
});

If ES6 isn't available, and the method does not support specifying a this value for its callback, you could bind the function to a this value:

this.data.forEach(function (region) {
  this.regionsChecked.push(region.regionName);
}.bind(this));
c.P.u1
  • 16,664
  • 6
  • 46
  • 41
  • Why would I use ES6 if it's only supported in super-modern browsers? – user5648283 Dec 20 '15 at 05:07
  • Some features of ES6 including arrow functions are available in Node.js (V8), albeit you could also use a transpiler like Babel. – c.P.u1 Dec 20 '15 at 05:09
  • If you are using ES6, `forEach` is deprecated. Just use a `for of` loop right away, and you won't have to care about `this` at all. – Bergi Dec 20 '15 at 13:04
0

All the above solutions are working, it's more like personal preference. For example if you check out Airbnb javascript style guide: https://github.com/airbnb/javascript#22.5

22.5 Don't save references to this. Use arrow functions or Function#bind.

// bad
function foo() {
    const self = this;
    return function () {
        console.log(self);
    };
}

// bad
function foo() {
    const that = this;
    return function () {
        console.log(that);
    };
}

// good
function foo() {
    return () => {
        console.log(this);
    };
}
barczag
  • 741
  • 6
  • 10