(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.