0

I'm facing for the first time OOP in JavaScript and all the troubles that comes with it...

I have this function/Object/class/whatever which has a method mainLoop() that should display some falling text - just like in the movie The Matrix. When I call it though I get undefined variables errors and using the debugger I see that inside mainLoop() this is pointing to Window instead of the object that called the method.

Here's the code:

function Matrix(config) {

    return {
        //[...lots of other vars...],
        drops: [],
        lines: [],
        //final string to put in the container
        str: "",

        mainLoop: function(){
            var tmp = "";
            //randomly create a "character drop"
            //(not if there's already a drop)
            for(var i = 0; i < this.cols; i++){
                if(this.drops[i] == 0 && Math.random() < this.freq){
                    this.drops[i] = irandom(this.rows) + 1;//new drop
                    tmp += randomChar();//output drop
                }
                else tmp += lines[0].charAt(i);
            }
            this.lines[0] = tmp; // <-------------- ERROR

            //update already created drops
            tmp = "";
            for(var j = 0; j < this.cols; j++){
                if(this.drops[j] > 0){
                    tmp += this.randomChar();
                    this.drops[j]--;
                }
                else tmp += " ";
            }
            this.lines[this.rowIndex] = tmp;
            this.rowIndex = (this.rowIndex+1) % this.rows;

            //render the entire text
            this.str = "";
            for(var l in this.lines)
                this.str += l + "<br/>";

            $(container).html = this.str;

        },

        start: function(){
            for(var i = 0; i < this.cols; i++)
                this.drops[i] = 0;
            timer = setInterval(this.mainLoop ,this.delay);
        },

        stop: function(){
            clearInterval(this.timer);
        },

        randomChar: function(){
            return this.chars.charAt(irandom(this.chars.length));
        },

        irandom: function(x){
            return Math.floor(Math.random()*x);
        }
    }
};

And then I call this function like this:

var config = {
    container: "#container",
    rows: 20,
    cols: 20,
    delay: 2000
};
var m = Matrix(config);
m.start();

The browser console says:

TypeError: this.lines is undefined

(code comment shows the exact point of the error). Furthermore, the debugger says that, at that point, this points to Window, not to m as I would expect... what's wrong with my reasoning? Thanks in advance for any help.

3
  • 2
    This is due to the setInterval call, see this answer Commented Dec 28, 2013 at 23:47
  • 1
    Try timer = setInterval(this.mainLoop.bind(this), this.delay); Commented Dec 28, 2013 at 23:58
  • Isn't it var m = new Matrix(config) ? Commented Dec 29, 2013 at 0:54

3 Answers 3

3

Alter your start function:

    start: function(){
        var self = this;
        for(var i = 0; i < this.cols; i++)
            this.drops[i] = 0;
        timer = setInterval(function() {
            self.mainLoop(); 
        }, this.delay);
    }

this was poiting at window because the scope has changed.

Sign up to request clarification or add additional context in comments.

Comments

2

Since JavaScript is prototype-based, maybe (if you haven't already) try doing it following this model:

function Matrix(config) {

    this.property = config.firstmember;
    this.property2 = config.secondmember;

    return function() { console.log('hello world') };

}

Matrix.prototype = {

    someMethod: function() {
        //do something
    },
    start: function() {
        //console.log('hello world');
    },
    stop: function() {
        //do something
    }

}

var config = {
    firstMember: 'foo',
    secondMember: 'bar'
}

var m = new Matrix(config);

//console output: "hello world"

/*var m = {
    property: 'foo',
    property2: 'bar',
    ____proto___: Matrix: {
            someMethod: function() {
                //do something
            },
            start: function() {
                //console.log('hello world');
            },
            stop: function() {
                //do something
            }
        }

}*/

Also, see the answer to this question regarding setInterval.

setInterval callback functions are members of the Window object; therefore, 'this' refers to the window. You will need to pass in a parameter of the current object to the callback that is inside setInterval. See the link above for more details.

Comments

1

If you need a reference to the calling object, I'd suggest passing it down as a parameter to the function.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.