1

I'm trying to create a class, and pass it to another class, and i'm running into issues with the prototype. I know I can use bind to get around this, but I can't figure out a way to have the prototype method bound to it's constructor on instantiation. This leaves me with something like this:

foo = new obj(); // has foo.method that depends on "this" being bound to obj
// pass foo.method to bar, with it's context bound to foo
bar = new obj2(foo.method.bind(foo)); //  obj2 uses foo.method as a "callback" internally. ugly. T_T

Here's a contrived example:

/**
* Base horn class. To be shared by cars, clowns, braggads, etc.
*/
var Horn = (function(){
 var Horn = function (noise){
    this.noise = noise;
  };
  Horn.prototype.sound = function(){
    return "*blowing horn* " + this.noise;
  };

  return Horn; // is there a way to bind here?
})();

/**
* Base car class. Needs a horn.
*/
var Car = (function(){
  var Car = function (model, horn) {
    this.model = model;
    this.horn = horn;
  };
  Car.prototype.drive = function(){
    return "i'm driving in my " + this.model + " " + this.horn();
  };
  return Car;
})();

/*
* Visualize output
*/
var term = document.getElementById('term');
term.say = function(message){
  this.innerHTML += message + "\n";
};

// create a horn for cars. 
var carHorn = new Horn('beep beep');
term.say(carHorn.sound()); // *blowing horn* beep beep


// pass the horn to a new Acura
var acura = new Car("acura", carHorn.sound);
term.say(acura.drive()); // i'm driving in my acura *blowing horn* undefined

// Pass the horn to a prius, but bind the horn first
var prius = new Car("prius", carHorn.sound.bind(carHorn)); // whooo bind.
term.say(prius.drive()); //i'm driving in my prius *blowing horn* beep beep

JS Bin

I've done a lot of reading on SO (this post was quite helpful), but I can't seem to find an elegant way to do this.

Also, if i'm going about this in a totally backwards way, let me know.

5
  • 2
    Why don't you pass a Horn, not a Horn method to the Car constructor? Then, you'd use this.horn.sound() instead of this.horn() Commented Jun 20, 2013 at 22:06
  • "but I can't figure out a way to have the prototype method bound to it's constructor on instantiation" Inside the constructor, you can iterate over all prototype methods and assign them bound to the same property name of the instance, i.e. this[method] = this[method].bind(this). Of course this creates a new copy of each method for each instance which kind of defeats the purpose of using prototype in the first place. I wouldn't do it. Commented Jun 20, 2013 at 22:08
  • @ian Ideally car.horn could be any function (even an anonymous one), so Car can just call it without knowing the function name. Commented Jun 20, 2013 at 22:08
  • @NickTomlin I know it's not my place to suggest stuff like this, but if you're using "classes", why not use them everywhere? Sure, it could be any function to call, but you actually have a Horn defined, why not use it? In real life, and in your program, I would think there's a "relationship" between cars and horns Commented Jun 20, 2013 at 22:09
  • in Car.prototype.drive instead of calling function from instance of Car, call it while creating new Car("acura", carHorn.sound()); Commented Jun 20, 2013 at 22:12

2 Answers 2

1

You can bind a method within a constructor:

var Horn = function (noise){
    this.noise = noise;
    this.sound = this.sound.bind( this );
};

The RHS will read it from the prototype and the LHS will write it directly on the object and it will shadow the one on the prototype when you reference it. You can still reference the unbound version with hornInstance.constructor.prototype.sound or Horn.prototype.sound.

This is usually done when you have no choice though, I.E. when passing a method as an event listener somewhere. In this case you could easily just pass the horn object around.

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

3 Comments

Let's say we were almost synchronous! :) But does your answer assume you still have a prototype method? I don't see why it's needed anymore.
@bfavaretto Well it's technically not needed. But some people and I prefer the reduced indentation level and keeping constructors simple.
I can't argue with that, your version does look a lot cleaner.
0

I'd usually pass the whole object, or the function output, as suggested in the comments to the question. However, what you're asking is possible. You just can't have the functions in the prototype, you need a separate (bound) function per instance:

var Horn = (function(){
 var Horn = function (noise){
     this.noise = noise;
     this.sound = function(){
        return "*blowing horn* " + this.noise;
     }.bind(this); // bind here
  };

  return Horn;
})();

http://jsfiddle.net/5xcHG/

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.