Javascript Question of the Day #21 [Talk::Overflow]
Source: Dev.to
This post explains a quiz originally shared as a LinkedIn poll.
Quiz Code
function Animal(name) {
this.name = name;
}
Animal.prototype = {
speak() {
return this.name + ' makes a sound';
}
};
const dog = new Animal('Rex');
console.log(dog.speak());
console.log(dog.constructor === Animal);
console.log(dog instanceof Animal);
console.log(dog.constructor === Object);
Output
Rex makes a sound
false
true
true
Explanation
Every function in JavaScript is automatically given a prototype object that contains a single non‑enumerable property: constructor, pointing back to the function itself. When you replace the entire prototype with a new object literal (Animal.prototype = { ... }), that replacement object is just a plain Object. Its constructor property is inherited from Object.prototype and therefore points to Object, not Animal.
dog.speak()– The instance has no ownspeakmethod, so JavaScript looks up the prototype chain, findsspeakon the replacement prototype, and calls it withthisbound todog.dog.constructor === Animal– The instance has no ownconstructor. The lookup reaches the replacement prototype (which also lacksconstructor), thenObject.prototype, whoseconstructorisObject. Hence the comparison isfalse.dog instanceof Animal– Theinstanceofoperator checks whetherAnimal.prototypeappears anywhere indog’s internal[[Prototype]]chain. Sincedog.__proto__is exactly the replacement prototype, the result istrue.dog.constructor === Object– As explained, the lookup resolves toObject.prototype.constructor, so the comparison istrue.
The Non‑Obvious Part
Developers often treat constructor and instanceof as two views of the same relationship, but they are not:
instanceofwalks the live prototype chain and checks for a specific prototype object.constructoris just a regular property that can be lost, overwritten, or inherited from the wrong place.
Replacing the entire prototype object severs the constructor link while leaving instanceof intact, creating an inconsistency.
Key Takeaways
-
Replacing
Fn.prototypeentirely destroys theconstructorlink. The new object literal inheritsconstructorfromObject.prototype, which points toObject. -
Always restore the constructor if you replace the prototype:
Animal.prototype.constructor = Animal; -
instanceofandconstructorcheck different things; they should not be used interchangeably for type checking.
Best Practices
-
Augment prototypes instead of replacing them. Use:
Animal.prototype.speak = function () { return this.name + ' makes a sound'; };This adds methods without losing the original
constructor. -
If you must replace the prototype, explicitly set the
constructorproperty back to the original function. -
Prefer ES6 class syntax, which handles prototype augmentation correctly and preserves the
constructorautomatically. -
Never rely on
constructorfor type checking in production. Useinstanceof,Symbol.hasInstance, or explicit type tags instead. Treatconstructoras an informational convenience, not a guarantee.