tags:

views:

21

answers:

1

Hi. I'm not very used to javascript's prototyping syntax so this might be very simple.

function MyClass(){
   this.init = function(input){
      this.input.onkeyup = function(){
         this.change();
      }
   }
}

Obviously I've left some things out here, but this.input refers to an HTML input element. The problem here is that this in this.change() will no longer refer to the instance of MyClass but to the HTML-element. How can I get the object instead of the element?

+1  A: 

Event handlers automatically point the this keyword to the element the event is firing on. ECMA-262 5th Edition attempts to combat situations like this by implementing an old technique of "binding" a function to a specific object:

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}

Usage:

function MyClass(){
   this.init = function(input){
      this.input.onkeyup = (function(){
         this.change();
      }).bind(this);
   }
}

The ECMAScript implementation is the same as the PrototypeJS implementation (for which the code is above).

You could also implement it on a per-class basis:

function MyClass(){
   this.bind = function(){ 
       var args = Array.prototype.slice.call(arguments),
           self = this,
           fn = args.shift();
       return function(){ 
         return fn.apply(self, 
           args.concat(Array.prototype.slice.call(arguments))); 
       }; 
   };
   this.init = function(input){
      this.input.onkeyup = this.bind(function(){
         this.change();
      });
   }
}

The archaic ;-) option is to just store a reference to this outside of the function:

function MyClass(){
   var self = this;
   this.init = function(input){
      this.input.onkeyup = function(){
         self.change();
      }
   }
}
Andy E
Should this be the preferred way instead of making use of a closure?
Felix Kling
@Felix Kling: I certainly think so, especially if you're doing it a lot. I added the closure solution anyway, to make the answer more complete.
Andy E
Thanks! All good solutions. Think i'll go on the archaic version for now since it's only in one place i need it.
Martin