16

How can I use "call" with "setInterval" to get an object literal to invoke one of its own methods?

Here's an example. This works, and I understand why it works. The timer object calls its own tick method once each second

var timer =
{ 
  start: function()
  {
    var self = this;
    setInterval(function(){self.tick();}, 1000);

  },

  tick: function()
  {
    console.log("tick!");
  }
};

timer.start();

I tried to simplify this code by using "call". This next example is the best that I came up with. But it doesn't work: the tick method is called only once, and then I get a type error.

var timer =
{ 
  start: function()
  {
    setTimeout.call(this, this.tick(), 1000);
  },

  tick: function()
  {
    console.log("tick!");
  }
};

timer.start();

I think I don't really understand how call works. Can anyone explain what I'm doing wrong?

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64
d13
  • 9,817
  • 12
  • 36
  • 44

2 Answers2

30

You are .calling .setInterval not your callback function which the browser calls:

setInterval( this.tick.bind(this), 1000 );

Should work. See .bind

xinthose
  • 3,213
  • 3
  • 40
  • 59
Esailija
  • 138,174
  • 23
  • 272
  • 326
  • With Safari 5.1.5 this gives me "TypeError: undefined is not a function". Firefox 8.0.1 gives me "uncaught exception: Illegal operation on WrappedNative prototype object." – d13 Jun 28 '12 at 14:14
  • @user1282216 see the link. I assume developers don't use outdated software for development but apparently I was wrong :P. The firefox error is interesting, can you give me a jsfiddle on that? – Esailija Jun 28 '12 at 14:16
  • @user1282216 nevermind I can reproduce that error in firefox 13, you are doing it wrong. Use the code `setInterval( this.tick.bind(this), 1000)` instead of `setInterval.call( this )` (that causes the error) – Esailija Jun 28 '12 at 14:25
  • do u know how can I add, some argument to my method ( tick )??, thanks im trying this: setInterval( this.tick("arg_1").bind(this), 1000 ); – Alberto Acuña Jan 18 '16 at 12:15
3

This is what I ended up with:

  var timer = {
    time: 0,
    start: function() {
      var timerTick = this.tick.bind(this);
      window.setInterval(function() {
        timerTick();
      }, 1000);
    },
    tick: function() {
      this.time += 1;
      console.log(this.time);
    }
  };

  timer.start();
d13
  • 9,817
  • 12
  • 36
  • 44