-1

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?

5
  • It's printing the word "result" in place of one or two? Commented Apr 11, 2013 at 14:36
  • They both loop under the name result and they increment each others i... Commented Apr 11, 2013 at 14:36
  • Oh, result is the name of the frame it is running within in jsfiddle. Your code is running in the global context and returning window.name. Commented Apr 11, 2013 at 14:45
  • this refers to the window object, and it happens that window.name in jsfiddle is result. Commented Apr 11, 2013 at 14:45
  • Why it doesn't refer to Looper?!? How can I fix it? Commented Apr 11, 2013 at 14:46

1 Answer 1

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;
});
Sign up to request clarification or add additional context in comments.

5 Comments

Why loop.call(that)? Shouldn't that.loop() do it?
@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.
Oh, right. Why is that IIFE there anyway... removing that would make things less awkward.
Nice, I fixed it with your helpfull answer! :)
@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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.