views:

90

answers:

2

In Javascript, every object has a prototype. Any prototype is an object, therefore any prototype has a prototype.

This is me:

var Person = function (name) {
 this.name = name;
}

Person.prototype = {
 walk: function () {
  alert(this.name  + ' is walking');
 }
}

var walter = new Person('Walter');

I can walk:

walter.walk() // => "Walter is walking"

I wonder if people can fly? Programmers are gods, I'll just make people able to fly:

var WingedAnimal = function () {
 this.hasWings = true;
}

WingedAnimal.prototype = {
 fly: function () {
  alert(this.name + ' is flying')
 }
}

var Person = function (name) {
 this.name = name;
}

Person.prototype =  {
 walk: function () {
  alert(this.name  + ' is walking');
 },
 prototype: new WingedAnimal()
}

var walter = new Person('Walter');

walter.walk() // => 'Walter is walking'

walter.fly();

TypeError: walter.fly() is not a function

OK then:

Person.prototype =  {
    walk: function () {
        alert(this.name  + ' is walking');
    }
}

Person.prototype.prototype = new WingedAnimal();

var walter = new Person('Walter');

walter.walk() // => 'Walter is walking'

walter.fly();

TypeError: walter.fly() is not a function

Is there really no way to do this? I mean, having a chain of prototypes rather than mixing multiple objects into a single prototype?

Not that I dislike mixing things together, but still...


To clarify my question:

At the moment I have already solved this problem with a function that I usually call mix and put in a namespace usually called CORE. The function copies the members of all the objects it's passed into the first object. My code usually looks like this:

var Constructor = function () {
 // stuff
}

CORE.mix(Constructor.prototype, SomeInterface, AnotherInterface, {
 //stuff that goes only into objects made with Constructor
});

Everything in SomeInterface, AnotherInterface and the object literal ends up into Constructor.prototype, precedence right to left. This is not, however, how I think Javascript should work. I should have, I think, a chain of prototypes, not just one prototype with a ton of stuff mixed into it.

When I call someObject.method, method should be searched into someObject; if it isn't there it should be searched into someObject.prototype; then in someObject.prototype.prototype; and so on until a prototype has an undefined prototype, then it should fail. This is how I understand it from this great explanation. Am I wrong? Is one prototype for each object really all we can use?

+3  A: 

I think you're misunderstanding the prototype property. While all objects do have an internal reference to their prototype, there's no way to get or set this directly in every browser. The prototype property is only useful when assigned to constructor functions.

Person.prototype = new WingedAnimal();

Person.prototype.walk = function () {
    alert(this.name  + ' is walking');
};

var walter = new Person('Walter');

walter.walk() // => 'Walter is walking'

walter.fly();
Tim Down
+2  A: 
Person.prototype= {
    walk: function () {
            alert(this.name  + ' is walking');
    },
    prototype: new WingedAnimal()
}

That doesn't work: the prototype property lives on the constructor function, not on the prototype object:

Person.prototype= new WingedAnimal();
Person.prototype.walk= function() {
    alert(this.name  + ' is walking');
};

However this is also flawed in that it's trying to base a class on an instance; this works for WingedAnimal because its constructor does nothing much, but it's a bad pattern (promulgated by many bad JS tutorials) that'll confuse any more complicated task.

See this question for an overview of prototyping in JavaScript.

bobince
That clarified some things, thanks. Would you say that mixing everything into the same prototype is a better approach?
Kaze no Koe
Well, whatever. You did answer, I'll sort the rest out myself
Kaze no Koe
One prototype for WingedAnimal and Person? I'm hoping that's only an example case and any real case would have to be judged on its own merits. Personally I prefer relatively shallow prototype trees to Java-style deep inheritance, but I don't know that I'd make a Person a WingedAnimal. (!)
bobince