简体   繁体   中英

Creating objects with methods using 'this' in JavaScript

I am a proficient c# programmer, and I have a little bit of experience with HTML and Javascript, but I can't seem to figure out objects.

I am attempting to create a loop, which just keeps updating until the counter reaches 5 then stops the loop. but in the Update method counter = NaN.

This is my exact code.

function LoginScreen() {
    this.IntervalID = null;
    this.counter = 0;

    this.Start = function () {
        this.IntervalID = setInterval(this.Update, 60 / 1000);
    };

    this.Stop = function () {
        clearInterval(this.IntervalID);
    };

    this.Update = function () {

        this.counter++;
        alert(this.counter);

        if (this.counter > 5) this.Stop();
    };

}

LS = new LoginScreen();
LS.Start();

The problem is scope of the inner this of your Start() , Stop() and Update() functions. Within those functions, this is referring to the function, and not your LoginScreen object.

To get around these problems, I like to use a little self variable to help with scope issues. That way, whatever is referring to the self variable will use the object. Here's what I mean:

function LoginScreen() {

    // add this for scope fun...
    var self = this;

    this.IntervalID = null;
    this.counter = 0;

    this.Start = function () {
        self.IntervalID = setInterval(self.Update, 60 / 1000); // updated...
    };

    this.Stop = function () {
        clearInterval(self.IntervalID); // updated...
    };

    this.Update = function () {
        self.counter++; // updated...
        alert(self.counter); // updated...

        if (self.counter > 5) self.Stop(); // updated...
    };
}

LS = new LoginScreen();
LS.Start();

Hope this makes sense!

You ran into the dreaded Javascript "this" problem.

Try changing your this.Update code to:

var self = this;
this.Update = function () {

        self.counter++;
        alert(self.counter);

        if (self.counter > 5) self.Stop();
    };

But wait there is more

This is a very common mistake in Javascript. I think everyone including me did this at one point. It is fairly easy to understand, though.

What's going on

When you call a function as a method of an object, you set its context to the object. That means that this inside this function will point to your context object.

MyObject = {};
MyObject.someValue = 1;

MyObject.myMethod = function() {
    console.log(this.someValue); // This will log "1" to the console, as expected
};

Now comes the tricky part: You can change the context of a function. Let's add some more lines of code here:

MyOtherObject = {};
MyOtherObject.someValue = 2;
MyOtherObject.myMethod = MyObject.myMethod;

When you now call MyOtherObject.myMethod you call the same function as if you would call MyObject.myMethod , but in one case this points to MyObject and in the other case it points to MyOtherObject .

Now, when you call setInterval(MyObject.myMethod, 1000) , the functions context will be set to window (technically, setInterval calls window.setInterval ) and since window does not have a property called someValue , it will just be undefined.

How to fix it

To fix this, you can create another reference to your LoginScreen object. It will always point to the same object inside the entire scope, unless you change it. You can then use it as an alternative to this without worrying about the context.

function LoginScreen() {
    this.IntervalID = null;
    this.counter = 0;

    // Create another reference to "this"
    var self = this;

    this.Start = function () {
        // The function behind "this.Update" will always be called with "window"
        // as its context.
        this.IntervalID = window.setInterval(this.Update, 60 / 1000);
    };

    this.Stop = function () {
        // This function is called as "self.Stop", therefore "this" points to
        // "self", which points to the right object, so you can use "this".
        clearInterval(this.IntervalID);
    };

    this.Update = function () {
        // Inside this function, "this" points to "window".
        // You therefore have to use the previously declared "self"
        // to point to the right object.
        self.counter++;
        alert(self.counter);

        if (self.counter > 5) self.Stop();
    };

}

LS = new LoginScreen();
LS.Start();

Further reference

this - Mozilla Developer Network Another explanation of the beviour of this in JavaScript, along with some functions to control it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM