0

What do I want to achieve?

I have an class called Looper. I want to give each object a name and an own looper.

Results I expect

Created Looper Object...
one
Created Looper Object...
two
one - 1
two - 1
one - 2
two - 2
one - 3
two - 3
one - 4
two - 4
one - 5
two - 5
.......

My code

With this code I expect it to work.. 

var Looper = (function (window, document, $) {

    this.i = 1;

    var Looper = function () {
        console.log('Created Looper Object...');
    }

    var getName = function () {
        return this.name;
    }

    var setName = function (newName) {
        this.name = newName;
    }

    var loop = function () {
        console.log(getName() + ' - ' + this.i);
        this.i = this.i + 1;
    }

    var startLoop = function () {
        window.setInterval(loop, 1000);
    }

    Looper.prototype = {
        getName: getName,
        setName: setName,
        start: startLoop
    }

    return Looper;
})(window, document, jQuery);

var one = new Looper();
one.setName('one');
console.log(one.getName());
one.start();

var two = new Looper();
two.setName('two');
console.log(two.getName());
two.start();

jsFiddle example

My results

But it doesn't.... 

Created Looper Object...
one
Created Looper Object...
two
result - 1
result - 2
result - 3
result - 4
result - 5
.......

Can someone tell me why it doesn't?

My problem is that is can set this.name for each object.

But I cannot set this.i for each object. They overtake each others i. Looks like this.i is static?!?!?

Also when I use console.log(two.getName()); it works. But within the loop this.name is result?

Ron van der Heijden
  • 14,803
  • 7
  • 58
  • 82

1 Answers1

2

You need to create the this.i = 1; property inside of the constructor function:

var Looper = function () {
    this.i = 1;
    console.log('Created Looper Object...');
}

In your current code the this keyword refers to the global object (window), so that you are actually creating a global variable (which is some kind of "static", yes).

A similar thing happens in the function called from setInterval, this is again set to the global object (that's the reason why it finds the number at all). You need to explicitly call your loop method on the Looper instance, for example by

var startLoop = function () {
    var that = this;
    window.setInterval(function() {
       loop.call(that); // "that" refers to the Looper object, while "this" does not
       // if "loop" were a method on the Looper, it's equivalent to
       // that.loop()
    }, 1000);
}

or via bind

var startLoop = function () {
    window.setInterval(loop.bind(this), 1000);
}

Also, inside the loop function you will need to call getName as a method on the current Looper object:

this.getName()

It seems to add a little confusion that all your functions/methods are not only accessible on (inherited) properties of the objects, but also as local variables in your module. Notice that JavaScript has no classes, and this does not work like in Java - you always need to explicitly distinguish between variables and properties. Your module should look more like this:

var Looper = (function() {

    function Looper() {
        this.i = 1;
        this.name = null;
        console.log('Created Looper Object:', this);
    }

    Looper.prototype.getName = function() {
        return this.name;
    };
    Looper.prototype.setName = function(newName) {
        this.name = newName;
    };
    Looper.prototype.start = function() {
        var that = this;
        window.setInterval(function() {
            console.log(that.getName() + ' - ' + that.i);
            that.i++;
        }, 1000);
    };

    return Looper;
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Why `loop.call(that)`? Shouldn't `that.loop()` do it? – Dagg Nabbit Apr 11 '13 at 14:59
  • @DaggNabbit: I had that at first, but then I noticed that his objects actually do not have a `.loop` method - it was not added to the prototype. – Bergi Apr 11 '13 at 15:03
  • Oh, right. Why is that IIFE there anyway... removing that would make things less awkward. – Dagg Nabbit Apr 11 '13 at 15:05
  • Nice, I fixed it with your helpfull answer! :) – Ron van der Heijden Apr 11 '13 at 15:07
  • @Bondye: Yes. `this` can refer to anything, like the the DOM node when the function is called as an event handler. Or to the global object (like in your case twice) when called from `setInterval/Timeout` or as a normal function. Or to an object, as you expect it in constructor functions and instance methods. – Bergi Apr 11 '13 at 15:10