# JS Tip of the Day: When the constructor Property Matters

**URL:** <https://forum.kirupa.com/t/js-tip-of-the-day-when-the-constructor-property-matters/643115>\
**Category:** web dev\
**Created:** [April 21, 2020, 12:06pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-when-the-constructor-property-matters/643115 "2020-04-21T12:06:46Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [April 21, 2020, 12:06pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-when-the-constructor-property-matters/643115/1 "2020-04-21T12:06:46Z")

</div>

**When the constructor Property Matters**  
Level: Advanced

When using inheritance with function-based constructors, you’ll often see that when setting up the `prototype`, the `constructor` property of the new `prototype` is reassigned to the constructor function getting the new `prototype`.

```javascript
function Scientist () {}
function Dexter () {}

// extends
Dexter.prototype = Object.create(Scientist.prototype);
Dexter.prototype.constructor = Dexter; // <- fix constructor

```

This is done because the original `constructor` property within the `prototype` gets overwritten when the `prototype` is replaced with a new object. If you didn’t do this, checking the `constructor` property of instances of that constructor would be incorrect.

```javascript
function Scientist () {}
function Dexter () {}

// extends
Dexter.prototype = Object.create(Scientist.prototype);

let dexter = new Dexter();
console.log(dexter.constructor); // Scientist (expected Dexter)

```

This fix, however, is not entirely necessary. The inner workings of JavaScript will not fail to create the instances from that constructor or do anything else incorrectly as a result of the `constructor` property referencing the wrong constructor in the example above. If you were to forget to fix the `constructor` property in this way (as seen above), you would probably never notice unless you had any reason to refer to that property directly yourself.

There are only a few cases where the value of `constructor` really does matter to JavaScript (as of ES2019). The first, and probably most pervasive, is with default species values.

For types that support species, the instance methods that acquire the species are going to be checking for the `Symbol.species` value on an instance’s `constructor` property. If `constructor` is wrong, any resulting species-created instance may be the wrong type. Common types that support and actively use species includes Array and Promise.

```javascript
class MyArray extends Array {}
let array = new MyArray(1,2,3);
console.log(array.map(x => x) instanceof MyArray); // true

class OtherArray extends Array {}
array.constructor = OtherArray;
console.log(array.map(x => x) instanceof MyArray); // false
console.log(array.map(x => x) instanceof OtherArray); // true

```

```javascript
class MyPromise extends Promise {}
let promise = MyPromise.resolve();
console.log(promise.then(x => x) instanceof MyPromise); // true

class OtherPromise extends Promise {}
promise.constructor = OtherPromise;
console.log(promise.then(x => x) instanceof MyPromise); // false
console.log(promise.then(x => x) instanceof OtherPromise); // true

```

Additionally, promises also check `constructor` values when using `Promise.resolve()`. If the value being resolved is already a promise of the same type from which `resolve()` is called - as determined by the value of it’s `constructor` property - instead of creating a new promise wrapping that value, that same promise is returned. If they do not match, a new promise instance is created of the promise type of the caller of `resolve()`.

```javascript
class MyPromise extends Promise {}
let orig = MyPromise.resolve();
let resolved = MyPromise.resolve(orig);
console.log(resolved === orig); // true

class OtherPromise extends Promise {}
orig.constructor = OtherPromise;
resolved = MyPromise.resolve(orig);
console.log(resolved === orig); // false
console.log(resolved instanceof MyPromise); // true
console.log(resolved instanceof OtherPromise); // false

```

Note that the change in `constructor` here didn’t change the kind of instance created by `resolve()` (`MyPromise.resolve()` still creates `MyPromise` instances), just that a new instance is returned rather than the original.

As with `Promise.resolve()`, `RegExp`, when used as a factory function (not using `new`), may also return the instance provided rather than creating a new instance from scratch. It too looks to the `constructor` property to see if there’s a match, and if not, a new RegExp instance is created.

```javascript
let orig = /orig/;
let created = RegExp(orig);
console.log(created === orig); // true

class OtherRegExp extends RegExp {}
orig.constructor = OtherRegExp;
created = RegExp(orig);
console.log(created === orig); // false
console.log(created instanceof RegExp); // true
console.log(created instanceof OtherRegExp); // false

```

One thing you may have noticed in these examples is that `class` was used to create alternate types, not normal constructor functions. That’s because each of the types we were working with are either exotic (Array) or have internal slots (Promise, RegExp) that `class` is able to correctly handle during initialization. It is unlikely you’d be extending these types with normal constructor functions so ultimately, in the end, there shouldn’t be much concern around not updating the `constructor` property in these cases (as `class` performs the constructor fix for you when extending). That’s not to say you shouldn’t do it, though, assuming you’re even using function constructors (`class` syntax takes care of it all for you).

More info:

- [constructor (property) on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
- [Symbol.species on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species)
- [Promise.resolve on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve)
- [RegExp on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
