69

In the following object, I have a problem using the 'this' reference:

function SampleObject(){
    this.addObject = function(object){...}
    ...
    // more code here
    ...
    this.addNewObjects= function(arr){
        arr.forEach( function (obj) {
            this.addObject(new Obj(obj.prop1, obj.prop2));
        });
    }
}

I'm assuming the context is changing and that 'this' refers the iterated 'obj', and not 'SampleObject'. I've solved the problem using a normal for loop however, i'm curuois to why this is not working, and would like to know if there is another way to do this.

HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
user3339411
  • 887
  • 1
  • 6
  • 10
  • Where/how do you call `SampleObject()`? – Danny Apr 14 '15 at 12:02
  • 1
    I'd recommend reading up on `this`: [here](http://toddmotto.com/understanding-the-this-keyword-in-javascript/) or [here](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/) – javinor Apr 14 '15 at 12:06
  • @javinor thanks, these articles were very helpfull. Function creates scope, and so 'this' is owned by the Window object, which is the default owner of 'this'. – user3339411 Apr 14 '15 at 13:46
  • 1
    This question isn't a duplicate of Owner of "this" at all. – Scott Hillson Feb 26 '19 at 21:26

2 Answers2

136

You can store this in variable:

var self = this;
this.addNewObjects = function(arr){
    arr.forEach(function(obj) {
        self.addObject(new Obj(obj.prop1, obj.prop2));
    });
}

or use bind:

this.addNewObjects = function(arr) {
    arr.forEach(function(obj) {
        this.addObject(new Obj(obj.prop1, obj.prop2));
    }.bind(this));
}

And side note, without those this will be window object not obj. This is always object that was created using new keyword or window object if it's normal function. In strict mode this will be undefined in this case.

UPDATE: and with ES6 you can use arrow function:

this.addNewObjects = function(arr) {
    arr.forEach((obj) => {
        this.addObject(new Obj(obj.prop1, obj.prop2));
    });
}

arrow functions don't have their own this and they get it from outer scope.

UPDATE2: from @viery365 comment you can use this as second argument to forEach and it will make context for the function:

this.addNewObjects = function(arr) {
    arr.forEach(function(obj) {
        this.addObject(new Obj(obj.prop1, obj.prop2));
    }, this);
}

You can read this on MDN forEach page

jcubic
  • 61,973
  • 54
  • 229
  • 402
  • 4
    In the case of `forEach()`(related to the question) one can also use the 'built-in' second parameter - `thisArg` after the callback. Example: `arr.forEach(callback, this);` [documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) – viery365 Jan 12 '19 at 02:26
  • @viery365 Oh didn't know that, you should add your own answer with our solution. That may be better for just `forEach()`. – jcubic Jan 12 '19 at 10:59
  • There is no option to answer for this particular question maybe because was marked as a duplicate. But anyway your answer is almost perfect and I also learnt from it. My comment was just a complement. – viery365 Jan 13 '19 at 03:44
2
const array1 = [
  {name : "john", age: 20}, {name : "sarah", age: 70}
  ];

array1.forEach(element => this.print(element));

print = (data) =>
{
  console.log(data.name);
}
// expected output: "john"
// expected output: "sarah"

There is a better way to do this

array.forEach(obj => this.functionName(params));
jcubic
  • 61,973
  • 54
  • 229
  • 402