Domanda

In the following snippet I try to access the property offset from within the member function shift(). As it seems, I cannot access it this way, because console.log reports Offset: NaN:

function shiftImg() {
  this.offset = 0;
  this.shift =
    function() {
      this.offset++;
      console.log("Offset: " + this.offset);
    };
}

productImg = new shiftImg;
window.setInterval(productImg.shift, 100);

However, converting the code above from a template paradigm to a closure paradigm works as I'd expect:

function shiftImg() {
  var offset = 0;
  return {
    shift: function() {
      offset++;
      console.log("Offset: " + offset);
    }
  }
}

productImg = shiftImg();
window.setInterval(productImg.shift, 100);


In my first example, why I cannot access offset via the operator this?


My Answer:
I'll post here my solution, as I cannot append a standalone answer. Browsing again into the mess of the horribly-written MDN's documentation, I learned of the bind method:

function shiftImg() {
  this.offset = 0;
  this.shift =
    function() {
      this.offset++;
      var img = document.getElementById('img');
      img.style.paddingLeft = this.offset + 'px';
      console.log("Offset: " + this.offset);
    };
}

productImg = new shiftImg;
window.setInterval(productImg.shift.bind(productImg), 100);
È stato utile?

Soluzione

The nested function doesn't have it's own this context (it'll simply refer to the window), so assign a variable to the this method within shiftImg to which you can refer in the nested function:

function shiftImg() {
  var self = this;
  this.offset = 0;
  this.shift =
    function() {
      self.offset++;
      console.log("Offset: " + self.offset);
    };
}

productImg = new shiftImg();
window.setInterval(productImg.shift, 100);

The reason you need to do this is because the call to setInterval which invokes the method, is run in a separate execution context, where this is equal to the window. If you called this.shift() from within shiftImg() you'll see that you it works just fine without the need to add self. See this MDN article for more.

Alternatively you pass an anonymous function to the callback method in setInterval:

window.setInterval(function() {
    productImg.shift();
}, 100); 

If you use objects and jQuery then you'll find into this problem quite a lot, and jQuery's $.proxy utility method makes doing similar things to above fairly easy.

Altri suggerimenti

In the first example, the context of this for the offset is not the same context as shiftImage. The second function closure changes the scope of this.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top