DEV Community

ValPetal Tech Labs
ValPetal Tech Labs

Posted on

Javascript Question of the Day #21 [Talk::Overflow]

Javascript Logo

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

🧠 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

  1. function Animal(name) { this.name = name; } — Declares a constructor function. At this point, Animal.prototype is automatically created with a constructor property that references Animal.

  2. Animal.prototype = { speak() { ... } } — Completely replaces the original Animal.prototype with a new object literal. This new object has speak as an own method, but it does not have a constructor property pointing to Animal. Its prototype is Object.prototype, so constructor resolves to Object.prototype.constructor, which is Object.

  3. const dog = new Animal('Rex') — Creates a new instance. The new operator sets dog.__proto__ to the current value of Animal.prototype (the replacement object). dog gets an own property name: 'Rex'.

  4. console.log(dog.speak())dog has no own speak method, so JavaScript walks to dog.__proto__ (the replacement prototype) and finds speak. Calls it with this bound to dog. Prints Rex makes a sound.

  5. console.log(dog.constructor === Animal)dog has no own constructor. Walks to dog.__proto__ (the replacement object). That object also has no own constructor. Walks to Object.prototype, which has constructor: Object. So dog.constructor is Object, not Animal. Prints false.

  6. console.log(dog instanceof Animal) — The instanceof operator checks: does Animal.prototype exist anywhere in dog's [[Prototype]] chain? dog.__proto__ is exactly Animal.prototype. Prints true.

  7. console.log(dog.constructor === Object) — As established, dog.constructor resolves to Object.prototype.constructor, which is Object. Prints true.

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

  1. Replacing Fn.prototype entirely destroys the constructor link. The new object literal inherits constructor from Object.prototype, which is Object. Always restore it: Animal.prototype.constructor = Animal.

  2. instanceof and constructor check different things. instanceof walks the [[Prototype]] chain looking for a specific prototype object. constructor is a plain property subject to normal prototype lookup — it can point anywhere.

  3. Augment prototypes instead of replacing them. Use Animal.prototype.speak = function() { ... } to add methods without losing constructor. If you must replace the prototype, always add constructor back.

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

  5. Never rely on constructor for type checking in production. Use instanceof, Symbol.hasInstance, or explicit type tags instead. Treat constructor as an informational convenience, not a guarantee.

Top comments (0)