This post explains a quiz originally shared as a LinkedIn poll.
🔹 The Question
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);
Hint: When you replace the entire prototype object with a plain object literal, think about what built-in property the original prototype had that the new one does not.
Follow me for JavaScript puzzles and weekly curations of developer talks & insights at Talk::Overflow: https://talkoverflow.substack.com/
🔹 Solution
Correct answer: A) Speaks, false, true, true
The output is:
Rex makes a sound
false
true
true
🧠 How this works
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 points to Object, not Animal.
Meanwhile, the instanceof operator doesn't care about the constructor property at all. It walks the internal [[Prototype]] chain of the left-hand operand and checks whether the right-hand operand's current .prototype appears anywhere in that chain. Since dog.__proto__ is the same object as Animal.prototype (the replacement), dog instanceof Animal is true — even though dog.constructor is Object.
This creates a dangerous inconsistency: instanceof says one thing, constructor says another.
🔍 Line-by-line explanation
function Animal(name) { this.name = name; }— Declares a constructor function. At this point,Animal.prototypeis automatically created with aconstructorproperty that referencesAnimal.Animal.prototype = { speak() { ... } }— Completely replaces the originalAnimal.prototypewith a new object literal. This new object hasspeakas an own method, but it does not have aconstructorproperty pointing toAnimal. Its prototype isObject.prototype, soconstructorresolves toObject.prototype.constructor, which isObject.const dog = new Animal('Rex')— Creates a new instance. Thenewoperator setsdog.__proto__to the current value ofAnimal.prototype(the replacement object).doggets an own propertyname: 'Rex'.console.log(dog.speak())—doghas no ownspeakmethod, so JavaScript walks todog.__proto__(the replacement prototype) and findsspeak. Calls it withthisbound todog. PrintsRex makes a sound.console.log(dog.constructor === Animal)—doghas no ownconstructor. Walks todog.__proto__(the replacement object). That object also has no ownconstructor. Walks toObject.prototype, which hasconstructor: Object. Sodog.constructorisObject, notAnimal. Printsfalse.console.log(dog instanceof Animal)— Theinstanceofoperator checks: doesAnimal.prototypeexist anywhere indog's[[Prototype]]chain?dog.__proto__is exactlyAnimal.prototype. Printstrue.console.log(dog.constructor === Object)— As established,dog.constructorresolves toObject.prototype.constructor, which isObject. Printstrue.
The non-obvious part: Developers often treat constructor and instanceof as two views of the same relationship. They aren't. instanceof checks the live prototype chain linkage. constructor is 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.
🔹 Key Takeaways
Replacing
Fn.prototypeentirely destroys theconstructorlink. The new object literal inheritsconstructorfromObject.prototype, which isObject. Always restore it:Animal.prototype.constructor = Animal.instanceofandconstructorcheck different things.instanceofwalks the[[Prototype]]chain looking for a specific prototype object.constructoris a plain property subject to normal prototype lookup — it can point anywhere.Augment prototypes instead of replacing them. Use
Animal.prototype.speak = function() { ... }to add methods without losingconstructor. If you must replace the prototype, always addconstructorback.ES6 classes handle this correctly. Class syntax never replaces the prototype object — it augments it. This is one of the subtle safety improvements that classes provide over manual constructor functions.
Never rely on
constructorfor type checking in production. Useinstanceof,Symbol.hasInstance, or explicit type tags instead. Treatconstructoras an informational convenience, not a guarantee.

Top comments (0)