Skip to content Skip to sidebar Skip to footer

`this.some_property` Becomes Undefined Inside Anonymous Callback Function

So I can't quite figure out why the variable this.tasks becomes undefined inside of the add event listener I have inside of my goal object. I have a feeling it might have something

Solution 1:

The scope changes when you enter that anonymous closure and 'this' changes. You can hack around it by doing

var self = this;

And then using self in place of this (eg):

functionGoal(name) {
    var self = this;

    /* ... */this.gDiv.addEventListener('click', function(){
        alert(self.tasks);              
    });

If you're using jQuery you could do something nicer:

this.gDiv.addEventListener('click', $.proxy(function() {
    alert(this.tasks);
 }, this));

Either way works just fine.

EDIT: In ES6, arrow functions can be used instead as they don't bind their own "this", so it becomes even simpler:

this.gDiv.addEventListener('click', () => {
    alert(this.tasks);
 });

Solution 2:

Here is a comparison of some methods (including your problem), to give you a taster, and to try and explain things a little.

// This is the problem that you have,// where `this` inside the anonymous function// is a different scope to it's parentfunctionTest1(something) {
  // `this` here refers to Test1's scopethis.something = something;
  setTimeout(function() {
    // `this` here refers to the anonymous function's scope// `this.something` is `undefined` hereconsole.log(this.something);
  }, 1000);
};

newTest1('Hello');

// This solution captures the parent `this` as `test2This`,// which can then be used inside the anonymous functionfunctionTest2(something) {
  var test2This = this;

  this.something = something;
  setTimeout(function() {
    console.log(test2This.something);
  }, 1000);
}

newTest2('World');

// This solution captures `this` as `test3This` in an `IIFE closure`// which can then be used in the anonymous function// but is not available outside of the `IIFE closure` scopefunctionTest3(something) {
  this.something = something;
  (function(test3This) {
    setTimeout(function() {
      console.log(test3This.something);
    }, 1000);
  }(this));
}

newTest3('Goodbye');

// This method requires that you load an external library: jQuery// and then use it's `$.proxy` method to achieve the basics of // Test3 but instead of being referred to as `test3This` the// outer scope `this` becomes the inner scope `this`// Ahh, that's much clearer?functionTest4(something) {
  this.something = something;
  setTimeout($.proxy(function() {
    console.log(this.something);
  }, this), 1000);
}

newTest4('Mum');
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

// This is approximately what jQuery's `$.proxy` does// but without having to load the whole libraryfunctionTest5(something) {
  this.something = something;
  setTimeout((function(func, context) {
    returnfunction() {
      func.call(context);
    };
  }(function() {
    console.log(this.something);
  }, this)), 1000);
}

newTest5('Dad');

// Lets create the proxy method as a reuseablefunctionproxy(func, context) {
  var args = Array.prototype.slice.call(arguments, 2);

  returnfunction() {
    return func.apply(
      context, 
      args.concat(Array.prototype.slice.call(arguments))
    );
  };
}

// and now using itfunctionTest6(something) {
  this.something = something;
  setTimeout(proxy(function() {
    console.log(this.something);
  }, this), 1000);
}

newTest6('Me want cookies');

Then we have Function#bind

functionTest7(something) {
  this.something = something;
  setTimeout(function() {
    // `this` was bound to the parent's `this` using bindconsole.log(this.something);
  }.bind(this), 1000);
};

newTest7('Num num');
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js"></script>

And most recently ES2015 Arrow functions

functionTest8(something) {
  this.something = something;
  setTimeout(() =>console.log(this.something), 1000);
};

newTest8('Whoop');

Solution 3:

In ES6, arrow functions were introduced, which do not bind their own this.

MDN for reference.

So creating an anonymous function using the arrow syntax is probably the easiest way to overcome this issue nowadays. It is supported by all major browsers currently, except IE.

Solution 4:

the keyword 'this' changes in it's meaning for an event handler against a constructor

please refer to the MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#As_a_DOM_event_handler

Post a Comment for "`this.some_property` Becomes Undefined Inside Anonymous Callback Function"