1

Possible Duplicate:
How do I make a callable JS object with an arbitrary prototype?

Let's say we have multiple individual functions that we can call individually in their own context; But they also inherit some other object's prototype. Like this:

//Here is the parent object:
var Human = function(){
    this.isAlive = true;
};
Human.prototype.say = function(what){
    alert(what + '!');
};

//These will inherit from it:
var ninja = function() {
    alert("I'm a ninja!");
}
var samurai = function(){
    alert("I'm a samurai!");
}

//Now, how can I make ninja and samurai behave like this:
ninja(); //I'm a ninja!
samurai(); //I'm a samurai!
ninja.say('Hello'); //Hello!

//And they should keep their inheritance. Like:
Human.prototype.die = function(){
    this.isAlive = false;
}

ninja.die();
ninja.isAlive == false;

samurai.isAlive == true;

In other words, is there a way to have two objects that inherit another object's prototype, but are still callable as functions?

Note: I'm gonna use this in Adobe ExtendScript (aka Crippled Javascript), and it doesn't know much modern javascript. Like, Object.defineProperty doesn't work in it. So, is there a normal, standard way to do this?

Community
  • 1
  • 1
Aria
  • 386
  • 1
  • 3
  • 15
  • I don't think you can do this without declaring a `new ninja()`, but maybe someone can prove me wrong. – lbstr Dec 13 '12 at 16:18
  • +1 good find -- I would say that that answer proves me wrong – lbstr Dec 13 '12 at 16:24
  • @apslillers Yeah, I don't these are quite the same question. – Aria Dec 13 '12 at 16:43
  • For the record, I don't think that's doable in old js. – Aria Dec 13 '12 at 16:59
  • Does it 100% ***have*** to use `.prototype`, or are you just looking for it to inherit static methods/properties? The answer depends on what you're looking for and why. – Norguard Dec 13 '12 at 17:20

2 Answers2

3

Using apsillers's linked question, I was able to get it working with one adjustment: Human's properties and methods are defined as an object:

Try it out: http://jsfiddle.net/lbstr/JZP2S/

The key is the HumanMaker function. At a basic level, it takes a function and adds the Human prototype to it. This allows you to invoke your function, get all of the properties from Human and eat it too. Here it is:

function HumanMaker(f) {
    var h = Human;
    h.__proto__ = f.__proto__;
    f.__proto__ = h;
    return f;
}

You would invoke it like this:

var ninja = HumanMaker(function() {
    alert("I'm a ninja!");
});

Here is the whole thing:

var Human = {
    isAlive: true,
    say: function(what){
        alert(what + '!');
    },
    die: function(){
        this.isAlive = false;
    }
};

function HumanMaker(f) {
    var h = Human;
    h.__proto__ = f.__proto__;
    f.__proto__ = h;
    return f;
}

//These will inherit from it:
var ninja = HumanMaker(function() {
    alert("I'm a ninja!");
});
var samurai = HumanMaker(function(){
    alert("I'm a samurai!");
});

//Now, how can I make ninja and samurai behave like this:
ninja(); //I'm a ninja!
samurai(); //I'm a samurai!
ninja.say('Hello'); //Hello!


ninja.die();
ninja.isAlive == false;

samurai.isAlive == true;​
lbstr
  • 2,822
  • 18
  • 29
0

I have always found the functional inheritance pattern much more easier to understand:

var human = function(){
    var me = {};
    var _isAlive = true;
    Object.defineProperty(me, "isAlive", {
        get: function() { return _isAlive}
    });

    me.say=function(what){
        if(_isAlive)
          alert(what+'!');  
        else
           throw new Error('I am dead!');                
    }
    me.die=function(){
      _isAlive = false;                
    }
    return me;
};

var person = function(){
    var me = human();
    return me;
};        

var ninja = function(){
    var me = human();
    me.say = function(what){
        if(me.isAlive)
          alert(what+', I am a ninja!');  
        else
           throw new Error('I am dead!');          
    };
    return me;
};

var myPerson = person();
myPerson.say('hi');

var myNinja = ninja();
myNinja.say('hello');

I have left a demo here: http://jsfiddle.net/vtortola/nbpPt/

Cheers.

vtortola
  • 34,709
  • 29
  • 161
  • 263
  • Nice code, but unless I haven't understood your code, I don't think it answers the problem. ninja isn't callable. And human isn't extendable. Like, if ninja is an instance of Human, and Human suddenly adopts a new prototype method, ninja should have that method too, but still be callable as a normal function. – Aria Dec 13 '12 at 16:42