0

I have this code:

function Keyboard() {

    this.log = $('#log')[0];
    this.pressedKeys = [];

    this.bindUpKeys = function() {
        $('body').keydown(function(evt) {
            this.pressedKeys.push(evt.keyCode);

            var li = this.pressedKeys[evt.keyCode];

            if (!li) {
                li = this.log.appendChild(document.createElement('li'));
                this.pressedKeys[evt.keyCode] = li;
            }

            $(li).text('Down: ' + evt.keyCode);
            $(li).removeClass('key-up');
        });
    }

    this.bindDownKeys = function() {
        $('body').keyup(function(evt) {
            this.pressedKeys.push(evt.keyCode);

            var li = this.pressedKeys[evt.keyCode];

            if (!li) {
                li = this.log.appendChild(document.createElement('li'));
            }

            $(li).text('Up: ' + evt.keyCode);
            $(li).addClass('key-up');
        });
    }

}

I get these errors:

TypeError: 'undefined' is not an object (evaluating 'this.pressedKeys.push')

It doesn't matter what I want to do with the Array, it just keeps giving me access errors, as if it doesn't exists inside the prototype.

What am I doing wrong? :( I'm just accessing the array as any other value inside the prototype). Are there problems with objects inside objects?

2 Answers2

2

The problem is that inside the event handler this is not what you think. You can bind the event handler function with the bind method (or, since it looks like you're using jQuery, $.proxy):

this.bindUpKeys = function() {
    var that = this;
    $('body').keydown($.proxy(function(evt) {
        //Use `this` as normal inside here
    }, this));
}

Or you can store a reference to this outside of the event handler e.g.

this.bindUpKeys = function() {
    var that = this;
    $('body').keydown(function(evt) {
        //Use `that` instead of `this` in here
    });
}
James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • Thanks, that seems to work :). I was totally thinking out of scope. I'm used to using programming languages more as of lately than scripting. I was totally ignoring the scope in this matter. Thanks again ^^ –  Jul 03 '12 at 11:47
0

as if it doesn't exists inside the prototype.

No, it does.

I'm just accessing the array

That's what you don't. this does not point to your Keyboard instance inside an event listener.

When the function is called as an event listener the DOM element will be the context (jQuery does that, too). See MDN's overview for the this keyword. You can use a closure-scoped variable to hold a reference to the actual instance, as for example described here (there are many questions about that).

Possible quick-fixes:

  • $('body').keydown( (function(){...}).bind(this))
  • var that=this; $('body').keydown(function(){ that.pressedKeys...; });
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375