0

As we know JavaScript has Prototypal inheritance instead of Classical one, which means every object has a [[Prototype]] property which can be used for inheritance through prototype chain.

However one part of this prototypal inheritance model that i'm not able to understand is the logic behind default prototype property that a function (or a class) object gets initially. i.e.

  //For classes
  class Dog {}
  Dog.prototype // {constructor: Dog}

  //For functions
  function Cat() {}
  Cat.prototype // {constructor: Cat};

What's the possible use of having this property contain a constructor property pointing to function itself? I understand one usage that any object created will get the constructor property and can be used to created further objects if the definition is somehow lost (like this):

function Dog(name) {
  this.name = name;
  alert(name);
}

let dog = new Dog("White Dog");

let dog2 = new dog.constructor("Black Dog");

But this doesn't justify such setting which is quite complicated to be honest(because functions/classes are the only objects with such a circular reference to itself). Is there any other reasoning behind this decision?

D_S_X
  • 1,351
  • 5
  • 17
  • 35
  • You can use `dog.constructor` to get the constructor function/class used to create the object – adiga Nov 12 '19 at 18:42
  • The `prototype` property is an object that has a use for any instance you create with the constructor: that prototype object will be the instance's parent in the prototype chain. – trincot Nov 12 '19 at 18:47
  • 1
    Before the `class` syntax was introduced, there was no other way to define members common to all instances of a "class" (e.g. methods), than to assign to the constructor's `prototype` property. So it is also a historical thing... – trincot Nov 12 '19 at 19:01
  • I don't think this does what you expect: `new Dog.constructor("return 1+1")() == 2`. To recap: functions are objects, and they have a prototype property you can stuff with members that get inherited when using `new` to invoke the function and return an object. function.prototype is mainly exposed so you can modify it, iterate it, etc. it's where the inheritance chains looks. – dandavis Nov 12 '19 at 19:04
  • @adiga yeah i did mention that usage in the post. wanted to know if there's anything else this is useful for – D_S_X Nov 12 '19 at 19:06
  • @adiga: no, you can't: `Dog.constructor == Function`, you're thinking of `objInstance.constructor` – dandavis Nov 12 '19 at 19:13
  • "*But this doesn't justify such setting which is quite complicated*" - why not? It's certainly useful sometimes, and it's free as it comes by default. – Bergi Nov 12 '19 at 19:22
  • @Bergi It is quite complicated if you try to visualize the resulting prototype relations and __proto__ chains. See the prototype relations for **function** in the answer image for example: https://stackoverflow.com/questions/58464218/javascript-inheritance-how-prototype-chain-works-between-native-prototypes. – D_S_X Nov 12 '19 at 19:32
  • @Bergi Not really impressed with any of the answers in duplicate post. Still doesn't justify the decision to have such a constructor property. – D_S_X Nov 12 '19 at 19:33
  • @VSX I think the visualisation in your question there is just fine. The one in georg's answer is quite messed up, but the logic behind the [[prototype]], `.prototype` and `.constructor`s is not really that complicated. There are [much better diagrams](https://stackoverflow.com/q/29155986/1048572) as well. – Bergi Nov 12 '19 at 19:52
  • @VSX What's the justification for not having that property? Just because it makes something hard to draw? – Bergi Nov 12 '19 at 19:54
  • @Bergi Thanks a lot. [this](https://stackoverflow.com/questions/29155986/javascript-diagram-to-explain-inheritance-proto-and-prototype) was helpful – D_S_X Nov 14 '19 at 19:59

1 Answers1

0

(Updated to answer the actual question, see old answer below)

Is there any other reasoning behind this decision?

I can only guess, but it probably comes from the design of the languages that influenced javascript. In pure prototype-based programming, there are no constructors at all. There's only the prototype object itself to define a "class", and it would have an init method to be called on instances derived from it. A pseudo-language example:

dog = object create()
dog init = (name) {
  this name = name
}
mydog = dog create()
mydog init("whitey")

Notice how mydog inherits from dog which inherits from object. The dog object has an init method, this is the natural link. A helper method new might bundle create and init together, to be called as mydog = dog new("blackey").

Now in JavaScript everything was made an object, even the functions/methods themselves. And to look more like Java (which was hip at the time), new was made an operator not an inherited method. For some reason, it was decided not to apply it to the prototype object, but to the constructor function instead - which was given a .prototype property for this. Maybe so that classes could be declared with a simple function? Or to enable inheritance by overwriting .prototype with a custom object? I do not know.

In any case, .constructor is the more natural one of the two circular properties. We could easily live without a .prototype:

 // assuming builtins:
 const object = Object.create(null)
 object.create = function() { return Object.create(this) }
 object.new = function() { const o = this.create(); o.constructor(); return o }

// we would use them as (assuming the object literal to inherit from `object`)
var Dog = {
  constructor(name) { this.name = name },
  woof() { alert(this.name + "makes: Woof!") }
}
var myDog = Dog.new("Whitey")
myDog.woof()

The power comes from the object being used as the [[prototype]] of all the instances being created with the new operator:

const mydog = new Dog("White Dog");
console.assert(Object.getPrototypeOf(mydog) === Dog.prototype)

This is the central object of your class, where all the shared methods live. The .constructor property among them is just a helpful (if rarely used) default. But you'd write

Dog.prototype.woof = function() {
    alert(this.name + "makes: Woof!");
};

and the method would be available through inheritance as

dog.woof();

Using class syntax to define the methods leads to just the same Dog.prototype object.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I understand why the prototype property is used. However i wanna know why this prototype has a such initial/default value with a constructor pointing to original function itself. – D_S_X Nov 12 '19 at 19:18
  • @VSX I might have misunderstood your question, but you were asking "*What's the logic behind the default `.prototype` property of a function/class?*"? – Bergi Nov 12 '19 at 19:19
  • @VSX And no, the `.constructor` property is not pointing to the prototype object itself, it's pointing to the constructor function. – Bergi Nov 12 '19 at 19:20
  • My bad. updated the title. Yeah i meant that only constructor pointing to original function. – D_S_X Nov 12 '19 at 19:21