5

In the following code, orange's constructor logs as its parent's constructor (Plant()) as opposed to Fruit() which is its. Why is this so?

(Sorry about the random objects. It's the middle of the night and I'm just learning some JavaScript. Didn't think too much about them to make sense in the real world, just typed them in as samples to understand prototypes better.)

function Plant(name, colour) {
    this.name = name;
    this.colour = colour;
}

Plant.prototype.print = function () {
    return "I'm a " + this.name.toLowerCase() + " and I'm " + this.colour.toLowerCase() + ".";
}

var mango = new Plant("Mango", "Orange");
console.log(mango.constructor);

function Fruit(type, isOrganic) {
    this.type = type;
    this.isOrganic = isOrganic;
}
Fruit.prototype = new Plant("Orange", "Orange");

var orange = new Fruit("staples", true);
console.log(orange.constructor);

I get a Plant(name, colour) for both console.log() calls whereas I think I should be getting Fruit(type, isOrganic) for the second one. What am I doing/understand incorrectly?

http://jsfiddle.net/eHZf8/

Update: Consistent with the above, if I do the following...

Fruit.prototype = {
    hello: "World"
};

...instead of what I did in the example above, I get Object() as the constructor for the object even though I create it with new Fruit().

Why is it that an object's constructor property contains the oldest function in the lineage that was used to build it as opposed to the latest?

Siddharth
  • 1,146
  • 3
  • 15
  • 28
  • 1
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain – Robert Harvey Jul 17 '14 at 21:37
  • 3
    [Don't use `new` to create prototypes!](https://stackoverflow.com/questions/12592913/what-is-the-reason-to-use-the-new-keyword-here) – Bergi Jul 17 '14 at 22:03
  • Bergi is correct, use Object.create and you're not re using parent constructor. More information information can be found here: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Jul 18 '14 at 03:16

1 Answers1

4

JS is a Prototype-based language. Objects aren't made and don't behave exactly the same as in Object Oriented languages.

What this means is that when you call...

Fruit.prototype = new Plant("Orange", "Orange");

You are defining that the Fruit "class" (though there aren't classes) is exactly the same as a Plant with with name => "Orange" and color => "Orange". Everything is copied, including the constructor.

Besides the problem of all Fruit now being oranges, one way to fix this would be to include this line...

function Fruit(type, isOrganic) {
    this.type = type;
    this.isOrganic = isOrganic;
}
Fruit.prototype = new Plant("Orange", "Orange");
Fruit.prototype.constructor = Fruit; // <--- Add this

Which makes Fruit use the Fruit() function as the constructor. Which is also passed down to all objects constructed with it.

  • Adding the line changes the Fruit.prototype.constructor to itself (the function that is), but seems like a hack. The built object is identical anyway (other than the fact that the `constructor` property is now enumerable) but yes it does point to the correct constructor (correct in my head, that is) because we assigned the value to the property. – Siddharth Jul 17 '14 at 21:20
  • 2
    It may seem hackish coming at it from an OOP point of view. But in Prototype based languages, there is no real "inheritance". We cannot say that Fruit is a "child class" of Plant, we must say Fruit is exactly the same as Plant, and then add in differences that make it unique. The constructor is one such difference, as the Fruit needs its own. For further reference, this way is one way that Mozilla recommends doing it in a [Tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance). – Matt Moehring Jul 17 '14 at 21:28
  • It breaks in the case of this fiddle. http://jsfiddle.net/6ZMPw/ It changes the first object's constructor to the new one due to the assignment. – Siddharth Jul 17 '14 at 21:34
  • 1
    @Siddharth `Second.prototype = first` is not good form -- speaking *very* generally, the `prototype` for a constructor function should be newly-created when being assigned. In the case of your fiddle, doing `Second.prototype = Object.create(first)` would work perfectly. This creates a new object to serve as a dedicated prototype for `Second`, and that dedicated object uses `first` as its own prototype. – apsillers Jul 17 '14 at 22:05
  • @MattMoehring: There is *real* inheritance. And it's not limited to classes only! – Bergi Jul 17 '14 at 22:08
  • 1
    @Siddharth Also, in your example, why do you even care that `first.constructor` is modified? It's just an object used as `Second.prototype` (to repeat: `first` is just an object, not a constructor function), so it absolutely *should* have its `constructor` property changed to whatever `Second.prototype.constructor` is. If you don't want changes to `Second.prototype` to change `first`, don't have them be the same object. – apsillers Jul 17 '14 at 22:10