Object.prototype.constructor
BaselineWidely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Theconstructor
data property of anObject
instance returns a reference to the constructor function that created the instance object. Note that the value of this property is a reference tothe function itself, not a string containing the function's name.
Note:This is a property of JavaScript objects. For theconstructor
method in classes, seeits own reference page.
Value
A reference to the constructor function that created the instance object.
Property attributes ofObject.prototype.constructor | |
---|---|
Writable | yes |
Enumerable | no |
Configurable | yes |
Note:This property is created by default on theprototype
property of every constructor function and is inherited by all objects created by that constructor.
Description
Any object (with the exception ofnull
prototype objects) will have aconstructor
property on its[[Prototype]]
. Objects created with literals will also have aconstructor
property that points to the constructor type for that object — for example, array literals createArray
objects, andobject literals create plain objects.
const o1 = {};o1.constructor === Object; // trueconst o2 = new Object();o2.constructor === Object; // trueconst a1 = [];a1.constructor === Array; // trueconst a2 = new Array();a2.constructor === Array; // trueconst n = 3;n.constructor === Number; // true
Note thatconstructor
usually comes from the constructor'sprototype
property. If you have a longer prototype chain, you can usually expect every object in the chain to have aconstructor
property.
const o = new TypeError(); // Inheritance: TypeError -> Error -> Objectconst proto = Object.getPrototypeOf;Object.hasOwn(o, "constructor"); // falseproto(o).constructor === TypeError; // trueproto(proto(o)).constructor === Error; // trueproto(proto(proto(o))).constructor === Object; // true
Examples
Displaying the constructor of an object
The following example creates a constructor (Tree
) and an object of that type (theTree
). The example then displays theconstructor
property for the objecttheTree
.
function Tree(name) { this.name = name;}const theTree = new Tree("Redwood");console.log(`theTree.constructor is ${theTree.constructor}`);
This example displays the following output:
theTree.constructor is function Tree(name) { this.name = name;}
Assigning the constructor property to an object
One can assign theconstructor
property of non-primitives.
const arr = [];arr.constructor = String;arr.constructor === String; // truearr instanceof String; // falsearr instanceof Array; // trueconst foo = new Foo();foo.constructor = "bar";foo.constructor === "bar"; // true// etc.
This does not overwrite the oldconstructor
property — it was originally present on the instance's[[Prototype]]
, not as its own property.
const arr = [];Object.hasOwn(arr, "constructor"); // falseObject.hasOwn(Object.getPrototypeOf(arr), "constructor"); // truearr.constructor = String;Object.hasOwn(arr, "constructor"); // true — the instance property shadows the one on its prototype
But even whenObject.getPrototypeOf(a).constructor
is re-assigned, it won't change other behaviors of the object. For example, the behavior ofinstanceof
is controlled bySymbol.hasInstance
, notconstructor
:
const arr = [];arr.constructor = String;arr instanceof String; // falsearr instanceof Array; // true
There is nothing protecting theconstructor
property from being re-assigned or shadowed, so using it to detect the type of a variable should usually be avoided in favor of less fragile ways likeinstanceof
andSymbol.toStringTag
for objects, ortypeof
for primitives.
Changing the constructor of a constructor function's prototype
Every constructor has aprototype
property, which will become the instance's[[Prototype]]
when called via thenew
operator.ConstructorFunction.prototype.constructor
will therefore become a property on the instance's[[Prototype]]
, as previously demonstrated.
However, ifConstructorFunction.prototype
is re-assigned, theconstructor
property will be lost. For example, the following is a common way to create an inheritance pattern:
function Parent() { // …}Parent.prototype.parentMethod = function () {};function Child() { Parent.call(this); // Make sure everything is initialized properly}// Pointing the [[Prototype]] of Child.prototype to Parent.prototypeChild.prototype = Object.create(Parent.prototype);
Theconstructor
of instances ofChild
will beParent
due toChild.prototype
being re-assigned.
This is usually not a big deal — the language almost never reads theconstructor
property of an object. The only exception is when using[Symbol.species]
to create new instances of a class, but such cases are rare, and you should be using theextends
syntax to subclass builtins anyway.
However, ensuring thatChild.prototype.constructor
always points toChild
itself is crucial when some caller is usingconstructor
to access the original class from an instance. Take the following case: the object has thecreate()
method to create itself.
function Parent() { // …}function CreatedConstructor() { Parent.call(this);}CreatedConstructor.prototype = Object.create(Parent.prototype);CreatedConstructor.prototype.create = function () { return new this.constructor();};new CreatedConstructor().create().create(); // TypeError: new CreatedConstructor().create().create is undefined, since constructor === Parent
In the example above, an exception is thrown, since theconstructor
links toParent
. To avoid this, just assign the necessary constructor you are going to use.
function Parent() { // …}function CreatedConstructor() { // …}CreatedConstructor.prototype = Object.create(Parent.prototype, { // Return original constructor to Child constructor: { value: CreatedConstructor, enumerable: false, // Make it non-enumerable, so it won't appear in `for...in` loop writable: true, configurable: true, },});CreatedConstructor.prototype.create = function () { return new this.constructor();};new CreatedConstructor().create().create(); // it's pretty fine
Note that when manually adding theconstructor
property, it's crucial to make the propertynon-enumerable, soconstructor
won't be visited infor...in
loops — as it normally isn't.
If the code above looks like too much boilerplate, you may also consider usingObject.setPrototypeOf()
to manipulate the prototype chain.
function Parent() { // …}function CreatedConstructor() { // …}Object.setPrototypeOf(CreatedConstructor.prototype, Parent.prototype);CreatedConstructor.prototype.create = function () { return new this.constructor();};new CreatedConstructor().create().create(); // still works without re-creating constructor property
Object.setPrototypeOf()
comes with its potential performance downsides because all previously created objects involved in the prototype chain have to be re-compiled; but if the above initialization code happens beforeParent
orCreatedConstructor
are constructed, the effect should be minimal.
Let's consider one more involved case.
function ParentWithStatic() {}ParentWithStatic.startPosition = { x: 0, y: 0 }; // Static member propertyParentWithStatic.getStartPosition = function () { return this.startPosition;};function Child(x, y) { this.position = { x, y };}Child.prototype = Object.create(ParentWithStatic.prototype, { // Return original constructor to Child constructor: { value: Child, enumerable: false, writable: true, configurable: true, },});Child.prototype.getOffsetByInitialPosition = function () { const position = this.position; // Using this.constructor, in hope that getStartPosition exists as a static method const startPosition = this.constructor.getStartPosition(); return { offsetX: startPosition.x - position.x, offsetY: startPosition.y - position.y, };};new Child(1, 1).getOffsetByInitialPosition();// Error: this.constructor.getStartPosition is undefined, since the// constructor is Child, which doesn't have the getStartPosition static method
For this example to work properly, we can reassign theParent
's static properties toChild
:
// …Object.assign(Child, ParentWithStatic); // Notice that we assign it before we create() a prototype belowChild.prototype = Object.create(ParentWithStatic.prototype, { // Return original constructor to Child constructor: { value: Child, enumerable: false, writable: true, configurable: true, },});// …
But even better, we can make the constructor functions themselves extend each other, as classes'extends
do.
function ParentWithStatic() {}ParentWithStatic.startPosition = { x: 0, y: 0 }; // Static member propertyParentWithStatic.getStartPosition = function () { return this.startPosition;};function Child(x, y) { this.position = { x, y };}// Properly create inheritance!Object.setPrototypeOf(Child.prototype, ParentWithStatic.prototype);Object.setPrototypeOf(Child, ParentWithStatic);Child.prototype.getOffsetByInitialPosition = function () { const position = this.position; const startPosition = this.constructor.getStartPosition(); return { offsetX: startPosition.x - position.x, offsetY: startPosition.y - position.y, };};console.log(new Child(1, 1).getOffsetByInitialPosition()); // { offsetX: -1, offsetY: -1 }
Again, usingObject.setPrototypeOf()
may have adverse performance effects, so make sure it happens immediately after the constructor declaration and before any instances are created — to avoid objects being "tainted".
Note:Manually updating or setting the constructor can lead to different and sometimes confusing consequences. To prevent this, just define the role ofconstructor
in each specific case. In most cases,constructor
is not used and reassigning it is not necessary.
Specifications
Specification |
---|
ECMAScript® 2026 Language Specification # sec-object.prototype.constructor |