Skip to main content

Command Palette

Search for a command to run...

JavaScript .constructor Demystified: How Objects Know Their Creator

Digging into .constructor: How JavaScript Objects Trace Their Origins

Published
•3 min read•View as Markdown
JavaScript .constructor Demystified: How Objects Know Their Creator

💡 Why Learn About .constructor?

In JavaScript, almost everything is an object—and every object has a story of where it came from. The .constructor property is that story. But its behavior isn't always obvious, especially when you start manipulating prototypes.

This deep dive shows you how .constructor works, where it comes from, when it breaks—and how to fix it.


🧱 1. Constructor Basics

When you create an object using a function and new, the object remembers its constructor:

function Person(name) {
  this.name = name;
}

const john = new Person('John');
console.log(john.constructor); // [Function: Person]

This works because every function has a .prototype object, and that prototype includes a .constructor reference by default.

🔍 2. Where .constructor Comes From

Even though you can access john.constructor, the property doesn’t live directly on the instance:

console.log(john.hasOwnProperty('constructor')); // false
console.log(Person.prototype.hasOwnProperty('constructor')); // true

The .constructor comes from Person.prototype, not john itself.


🧬 3. The Prototype Relationship

By default, a function’s prototype points back to the function itself via .constructor:

console.log(Person.prototype.constructor === Person); // true
console.log(john.constructor === Person); // true

This circular reference is what allows objects to identify the function that created them.


⚠️ 4. The Danger of Replacing prototype

Here's where things often go wrong:

function Person(name) {
  this.name = name;
}

Person.prototype = {
  sayHello: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

const john = new Person('John');
console.log(john.constructor); // [Function: Object] ❌

By replacing the whole prototype object, we accidentally removed the .constructor reference!

✅ Fix #1: Restore the .constructor

Person.prototype = {
  constructor: Person,
  sayHello: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

✅ Fix #2: Add methods directly instead of overwriting

Person.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}`);
};

🔧 5. Practical Uses for .constructor

📌 Type Checking

function checkType(val) {
  if (val.constructor === Array) {
    console.log('Array');
  } else if (val.constructor === Object) {
    console.log('Plain object');
  } else {
    console.log(`Instance of ${val.constructor.name}`);
  }
}

⚠️ Note: instanceof is generally more reliable for deep inheritance trees.

🔁 Object Copying

function clone(obj) {
  return new obj.constructor(obj);
}

🧬 Inheritance Checks

function isChildOf(child, parent) {
  return child.constructor === parent || child instanceof parent;
}

🎯 6. Special Cases to Watch Out For

🔹 Primitives

const num = 42;
console.log(num.constructor); // [Function: Number]

This works because JavaScript temporarily wraps primitives in objects via autoboxing.

🔹 Object.create(null)

const obj = Object.create(null);
console.log(obj.constructor); // undefined

No prototype = no .constructor.


🧠 7. Best Practices

  • ✅ Avoid replacing the entire prototype unless necessary

  • ✅ Always reset .constructor if you do

  • ✅ Use instanceof for complex type checking

  • ✅ Understand .constructor but don’t over-rely on it


🏁 Conclusion

.constructor gives every object a link back to its origin. Misusing it can cause confusing bugs, but understanding it unlocks better type checking, debugging, and OOP patterns.

Learn the rules, and you can bend them wisely.

Mastering .constructor brings you closer to understanding how JavaScript really works under the hood.


Would you like a side-by-side diagram of the prototype chain with .constructor behavior included?