# JS Tip of the Day: Mixing class and function Constructors

**URL:** <https://forum.kirupa.com/t/js-tip-of-the-day-mixing-class-and-function-constructors/643264>\
**Category:** web dev\
**Created:** [June 14, 2020, 1:46pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-mixing-class-and-function-constructors/643264 "2020-06-14T13:46:45Z")\
**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:** [June 14, 2020, 1:46pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-mixing-class-and-function-constructors/643264/1 "2020-06-14T13:46:45Z")

</div>

**Mixing class and function Constructors**  
Version: ES2015 (class, Reflect)  
Level: Advanced

For the most part, when creating your own constructor functions, you’re going to want to prefer the `class` syntax. It’s cleaner syntax and ability to easily extend builtins properly gives it an advantage over older, function-based constructors. However, there may be times when you’ll need to work with both, whether it be integrating with an older codebase, one of those obscure times when you can’t use `class` (e.g. the constructor needing to be callable as a function without `new`), or some other unexpected circumstance.

The good news is, `class` syntax works pretty well with other constructors no matter where they come from. If you need a `class` to extend a constructor defined with `function`, that should just work.

Consider a `Dog` constructor extending an `Animal` constructor. Both will have a data property and a method that can be used to show that a Dog instance gets correctly instantiated going through both constructors and inheriting from both prototypes.

```javascript
function Animal (name) {
    this.name = name;
}

Animal.prototype.logName = function () {
    console.log(this.name);
}

class Dog extends Animal {
    constructor (name, breed) {
        super(name);
        this.breed = breed;
    }
    logBreed () {
        console.log(this.breed);
    }
}

let dog = new Dog('Fido', 'Pointer');
dog.logName(); // Fido
dog.logBreed(); // Pointer

```

As expected, the output is correct. This shouldn’t be too surprising as `class` definitions are functions too and they were designed to be backwards compatible

But `class` definitions aren’t _exactly_ like other functions. They’re different enough that they lack compatibility going the other way around - a `function` constructor inheriting from a `class`.

```javascript
class Animal {
    constructor (name) {
        this.name = name;
    }
    logName () {
        console.log(this.name);
    }
}

function Dog (name, breed) {
    Animal.call(this, name); // super()
    this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.logBreed = function () {
    console.log(this.breed);
}

let dog = new Dog('Fido', 'Pointer');
// TypeError: Class constructor Animal cannot be invoked without 'new'

```

In its attempt to call the superclass constructor, `Dog` will fail here, throwing an error. This is because `Animal` can’t be called like a normal function. Being a `class` constructor, it can only be called with `new`.

So how do `function` constructors call their version of `super()` with `class` constructors? The simple answer is: they don’t. Another approach is needed.

Luckily, we’re saved by the fact that implicit constructor returns (returning `this`) can be overridden. This would allow us to, instead of passing the value of `this` up to the superclass to get updated, create an instance of the superclass to represent the new `this` and update that with the properties of the current constructor. Then, instead of allowing the implicit `this` to be returned, return the updated instance of the superclass explicitly.

```javascript
function Dog (name, breed) {
   let self = new Animal(name); // self replaces this
   self.breed = breed;
   return self;
}

```

While this creates a new instance with both the Animal and Dog data properties, it doesn’t have the Dog’s methods because as an Animal instance, `self` doesn’t inherit from Dog. That can be fixed easily enough with a call to `Object.setPrototypeOf()`.

```javascript
function Dog (name, breed) {
   let self = new Animal(name);
   Object.setPrototypeOf(self, Dog.prototype);
   self.breed = breed;
   return self;
}

```

This will get the job done, but it can be cleaned up a little using `Reflect.construct()` and `new.target`. `Reflect.construct()` is a function which creates instances through `new` and optionally allows you to set the prototype based on an additional constructor. `new.target` represents the constructor used when `new` was called. This can be used in super constructors to know whether or not they were called with `new` or some other subclass was. If `new` (or `Reflect.construct()`) was not used to invoke a function, `new.target` becomes undefined. `new.target` can be used with `Reflect.construct()` to reduce the first to lines in the constructor to just one.

```javascript
function Dog (name, breed) {
   let self = Reflect.construct(Animal, [name], new.target);
   self.breed = breed;
   return self;
}

```

The complete, working code then becomes.

```javascript
class Animal {
    constructor (name) {
        this.name = name;
    }
    logName () {
        console.log(this.name);
    }
}

function Dog (name, breed) {
    let self = Reflect.construct(Animal, [name], new.target);
    self.breed = breed;
    return self;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.logBreed = function () {
    console.log(this.breed);
}

let dog = new Dog('Fido', 'Pointer');
dog.logName(); // Fido
dog.logBreed(); // Pointer

```

While this is great, and everything is working as it should, our story doesn’t end here. So far we’ve only managed to take care of the superclasses. But we also don’t want to ignore the subclasses.

If you haven’t guessed already, subclassing with `class` constructors still _just work_, this especially thanks to the use of `new.target` in `Dog`.

```javascript
class ShowDog extends Dog {
    constructor (name, breed, hairStyle) {
        super(name, breed); // automatically passes new.target onto Dog
        this.hairStyle = hairStyle;
    }
    logHairStyle () {
      	console.log(this.hairStyle);
    }
}

let dog = new ShowDog('Rufus', 'Poodle', 'Continental');
dog.logName(); // Rufus
dog.logBreed(); // Poodle
dog.logHairStyle(); // Continental

```

With `function` constructors, things are, once again, a little more complicated. First, `Dog`, despite being a function constructor itself, is now passing an instance back from its constructor rather than relying on the existing `this`. This means a subclass `function` constructor would need to take that returned value and use that in place of its own `this` that it would normally pass through `Dog`.

```javascript
function ShowDog (name, breed, hairStyle) {
    let self = Dog(name, breed);
    self.hairStyle = hairStyle;
    return self;
}

```

But now there’s another problem. Since `Dog` is being called as a function (which is allowed), it’s `new.target` will be undefined calling `Reflect.construct()` inside `Dog` to fail. This can be corrected by calling `Dog` in `ShowDog` with `new`, but then the `new.target` value would be `Dog` instead of the expected `ShowDog`. To fix this, the subclass would now also need to use `Reflect.construct()` to make sure it can pass the correct `new.target` along to the `Dog` constructor.

```javascript
function ShowDog (name, breed, hairStyle) {
    let self = Reflect.construct(Dog, [name, breed], new.target);
    self.hairStyle = hairStyle;
    return self;
}

```

And with that, everything should now now work.

```javascript
function ShowDog (name, breed, hairStyle) {
    let self = Reflect.construct(Dog, [name, breed], new.target);
    self.hairStyle = hairStyle;
    return self;
}
ShowDog.prototype = Object.create(Dog.prototype);
ShowDog.prototype.constructor = ShowDog;

ShowDog.prototype.logHairStyle = function () {
	console.log(this.hairStyle);
};

let dog = new ShowDog('Rufus', 'Poodle', 'Continental');
dog.logName(); // Rufus
dog.logBreed(); // Poodle
dog.logHairStyle(); // Continental

```

What’s nice about the approach with `Reflect.construct()` is that it will work for any kind of superclass, even exotic builtins. The downside is that you’re creating two instances for each constructor, one from `Reflect.construct()`, and the other automatic instance getting assigned to `this` that gets handily ignored. This is another reason to prefer `class` where possible.

More info:

- [Classes on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
- [Functions on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions)
- [Reflect.construct() on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct)

* * *

More tips: [JavaScript Tips of the Day](http://forum.kirupa.com/t/javascript-tip-of-the-day/641803/1)
