views:

92

answers:

2

I'm writing an online game which allows a user to progress from one puzzle to the next, and if the user makes mistakes, each puzzle has a start again button to allow the user to start just that puzzle from scratch. A simplified version of the code's structure is below:

function puzzle(generator) {

    this.init = function() {
        this.generator = generator;
        ...
        this.addListeners();
    }

    //fires when the puzzle is solved
    this.completed = function() {
       window.theSequence.next();
    }

    this.empty = function() {
        //get rid of all dom elements, all event listeners, and set all object properties to null;
    }

    this.addListeners = function() {
       $('#startOver').click(function() {
            window.thePuzzle.empty();
            window.thePuzzle.init();
       });
    }
    this.init();
}

function puzzleSequence(sequenceGenerator) {

    this.init = function() {
        //load the first puzzle
        window.thePuzzle = new puzzle({generating json});

    }

    this.next = function() {
        //destroy the last puzzle and create a new one
        window.thePuzzle.empty();
        window.thePuzzle = new puzzle({2nd generating json});
    } 

}

window.theSequence = new puzzleSequence({a sequence generator JSON});

The problem I have is that if the user has progressed to the second puzzle, if they click start over it loads the first puzzle rather than the second. After a bit of debugging I've worked out that 'this', when used in methods by the second puzzle, for some reason still holds a reference to the first puzzle, but 'window.thePuzzle' - which should be the same as this - correctly refers to the second puzzle.

Why is 'this' persisting in referrring to the first one?

Let me know if you need more code samples

+1  A: 

$('#startOver').click(this.empty);

You've taken the empty method and detached it from this to pass as a plain unbound function to jQuery. When it gets called back, it will have no reference to the original value of this. In fact, when a function is called unbound, this will refer to window, so you'll be scribbling what you think are properties onto the globals.

JavaScript doesn't bind methods in the same way as other languages. See eg. this answer for an explanation of what it actually does. This confuses many people; personally I consider it one of JavaScript's worst flaws.

bobince
This is kinda what I'd expect it to be, but I've checked using console.log and 'this', in this specific context, somehow still refers to the old version of window.thePuzzle
wheresrhys
There still isn't enough code to reproduce the problem, but my suspicion would be somewhere in the code you have elided you are using `window.thePuzzle` in code that is called by the `puzzle` constructor, such as `init` or `addListeners`. At that point, the `puzzleSequence` code that says `window.thePuzzle= new puzzle` won't have written the new object to `window.thePuzzle` yet — it can't, until the constructor has finished executing.
bobince
A: 

There is a very good (and clear) description of exactly how the this reference is treated in different contexts over at Quirksmode.

Andrzej Doyle