The ES6 class Inheritance chain does not properly utilize the instanceof keyword

My curiosity lies in understanding why the instanceof operator fails to work properly for the inheritance chain when there are multiple chains of inheritance involved.

(optional read)

How does the instanceof operator function?

When using obj instanceof Constructor, the instanceof operator essentially checks if the 'prototype' property of the Constructor function is found within the prototype chain of the obj. If it is found, true is returned; otherwise, false is returned.


In the code snippet below, we observe that BTError inherits from Error (1.) while SomeError extends from BTError (3.).
However, it appears that despite expectations (4.), the instanceof operation results in false for

new SomeError() instanceof BTError
, which should ideally return true.

class BTError extends Error {}
console.log('1.', Reflect.getPrototypeOf(BTError.prototype) === Error.prototype); // 1. true
console.log('2.', new BTError() instanceof Error); // 2. true

console.log('');

class SomeError extends BTError {}
console.log('3.', Reflect.getPrototypeOf(SomeError.prototype) === BTError.prototype); // 3. true
console.log('4.', new SomeError() instanceof BTError); // 4. false

console.log('');

class SpecificError extends SomeError {}
console.log('5.', Reflect.getPrototypeOf(SpecificError.prototype) === SomeError.prototype); // 5. true
console.log('6.', new SpecificError() instanceof Error); // 6. true
console.log('7.', new SpecificError() instanceof BTError); // 7. false
console.log('8.', new SpecificError() instanceof SomeError); // 8. false


Question

Am I missing something significant here or is the behavior of the instanceof operator simply peculiar?

Answer №1

Focusing on the final aspect of the provided example

You are utilizing BabelJS to convert this code for compatibility

class BTError extends Error {}
class SomeError extends BTError {}
class SpecificError extends SomeError {}

console.log('6.', new SpecificError() instanceof Error);
console.log('7.', new SpecificError() instanceof BTError);
console.log('8.', new SpecificError() instanceof SomeError);

This represents the transcribed version of the aforementioned code

'use strict';

function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

function _possibleConstructorReturn(self, call) {
    if (!self) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return call && (typeof call === "object" || typeof call === "function") ? call : self;
}

function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

var BTError = function(_Error) {
    _inherits(BTError, _Error);

    function BTError() {
        _classCallCheck(this, BTError);

        return _possibleConstructorReturn(this, (BTError.__proto__ || Object.getPrototypeOf(BTError)).apply(this, arguments));
    }

    return BTError;
}(Error);

var SomeError = function(_BTError) {
    _inherits(SomeError, _BTError);

    function SomeError() {
        _classCallCheck(this, SomeError);

        return _possibleConstructorReturn(this, (SomeError.__proto__ || Object.getPrototypeOf(SomeError)).apply(this, arguments));
    }

    return SomeError;
}(BTError);

var SpecificError = function(_SomeError) {
    _inherits(SpecificError, _SomeError);

    function SpecificError() {
        _classCallCheck(this, SpecificError);

        return _possibleConstructorReturn(this, (SpecificError.__proto__ || Object.getPrototypeOf(SpecificError)).apply(this, arguments));
    }

    return SpecificError;
}(SomeError);

console.log('6.', new SpecificError() instanceof Error); 
console.log('7.', new SpecificError() instanceof BTError); 
console.log('8.', new SpecificError() instanceof SomeError); 

The issue appears to arise from the _inherit method, which sets subClass.prototype to an object that merges both the superClass.prototype and additional default properties.

Due to this chain of prototypes, inheritance functions properly but the instanceof operator fails to traverse it by reference, resulting in outcomes where you expect false instead of true.

Evidently, as documented in this bug report, this behavior is acknowledged as a known limitation, and a suggested workaround involves using babel-plugin-transform-builtin-extend

Answer №2

Encountered a similar issue with TypeScript recently. Managed to resolve it by including the code below in the constructor of the class right after the super calls:

Object.setPrototypeOf(this, YOUR_CLASS_HERE.prototype);

Hope this solution proves useful for you as well.

Answer №3

In my experience, I found that using the instanceof operator did not yield the expected results when compiling with a target of "es5". However, switching the target to "es6" resolved the issue and provided the correct output.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using regex to confirm prices are accurate

Can anyone assist me with validating input using regEx in Vue? I'm struggling to create one and haven't been able to find the correct pattern online for what I need. The specific validation I am attempting is for a price value that should be a f ...

Is it possible to create a custom options array in React-Select?

I've been working with react-select using the package from . The required format for the options prop is {value:something, label:something}. I have a list of objects with additional key-value pairs and I'm wondering if there's a way to avoi ...

The ExpressJS EJS issue arises when trying to access a property that is undefined

I'm new to NodeJS and seeking assistance. I am working on a website where users can promote their virtual conferences for others to see. I have set up a form with the POST method, where the data gets pushed into an array and then displayed in an EJS f ...

Encountered an issue while trying to use Figma's spellchecker extension

Despite following the instructions in the readme carefully, I am facing difficulties running the Figma spellchecker extension. Executing npm run build goes smoothly. But when I try to run npm run spellcheck, I encounter an error message in the console: co ...

The data in my JSON string is not fully received through the HTTP GET request

Whenever I send my array to the PHP file, it receives incomplete data. The content of my 'arr' variable is as follows: [["╪▒┘à┘╛┘╪د","67126881188552864","Empty,Empty,Empty,Empty,8644,-360,-4,8691,-3.48,-313,1015,4.334 M,1392/12/2 ...

What is the best way to utilize TypeScript module augmentation with material-ui components?

I have gone through the answers provided in this source and also here in this link, but it appears that they are outdated. I attempted to enhance the type definition for the button component in various ways, including a separate typings file (.d.ts) as we ...

Issue with vue.js not recognizing the 'require' function

I am a newcomer to Vue and I am trying to create a basic SPA using Vue without vue-router. Following the example of vue-2.0-simple-routing-example, I am attempting to load pages using require(dynamicPathToFile+'.vue'). However, this approach is n ...

Can the console logs be disabled in "Fast Refresh" in NextJS?

When I'm running multiple tests, my browser's console gets cluttered with messages every time a file is saved. Is there a way to disable this feature? For example: [Fast Refresh] completed in 93ms hot-dev-client.js?1600:159 [Fast Refresh] rebuil ...

Update the canvas box's color when you interact with it by clicking inside

I'm in the process of developing a reservation system and I'm looking to implement a feature where the color of a Canvas changes when clicked. The goal is for the color to change back to its original state when clicked again. Snippet from my res ...

Inadequate completion of Object.create() method

Here's the code snippet: //Note: x is being pulled from an external source and contains certain values var x = [{ name: 'Michael Lovesllamas Lankford', created: 1338420951.11, laptop: 'pc', laptop_version: null, userid: &apos ...

Generate an interactive pie chart with visually appealing animations using jQuery, without any actual data

My task involves creating a pie chart to visually display different categories. However, the challenge is that the chart does not contain any data, ruling out options like Google charts or other data-driven chart makers. As a solution, I have turned the pi ...

Unable to generate new entries with HTML Form

I've been working on creating a simple form with the ability to add new seasons or entries that will be posted to a database, but I've hit a roadblock. Whenever I try to run it, the "Add more Episodes" buttons for new seasons don't seem to w ...

What is the best way to have an HTML radio button automatically display as selected upon loading if the stored value is "on"?

Utilizing Javascript alongside html: I am facing an issue where a list containing radio buttons is dynamically loaded based on stored data when the page launches. Despite the stored value of the radio being set to "on", the radio button does not show up a ...

encountering an issue with server-side rendering of React causing an error

Node.js has been a bit of a challenge for me, especially when it comes to working with react and express. I have been struggling to find comprehensive tutorials and troubleshooting resources, leading me to ask minimal questions in the correct manner. While ...

What could be the reason for the malfunctioning dropdown menu in my navigation bar upon clicking it?

After spending hours practicing creating a navbar using Bootstrap 3.3.7, I've hit a roadblock - the dropdown is not working when clicked on. It's frustrating because I have double-checked all my scripts and ensured that I have the latest version ...

Click event not functioning in programmatically loaded HTML

I am facing an issue with a JSON file that contains the page content I am trying to load. The link within it appears as follows: <a data-ng-click='foo()'>Bar</a> When I load this page content into the HTML page: <p class="body" ...

Avoiding scrolling when a button (enveloped in <Link> from react-scroll) is pressed in React

Currently, I am implementing the smooth scroll effect on a component using react-scroll. However, adding a button inside the component to create a favorite list has caused an issue where the smooth scroll effect is triggered upon clicking the button. Is ...

I am seeking assistance in transmitting data to my server utilizing Ajax, PHP, and mySQL without relying on a form

I have been researching tutorials on how to work with JavaScript without using forms. Currently, I have the JavaScript code that maps my answers based on clicks and generates an array shown in an alert. However, I am unsure if the Ajax request is sending i ...

Calculating the total value in a Laravel database

Is there a way for me to calculate the number of apartments in a project based on the floor they are located on? This is db $table->id(); $table->unsignedBigInteger('project_building_id')->nullable(); $table->unsignedBigInteger(&apos ...

Guiding you on exporting a Typescript class with parameters in Node.js

Trying to find the Typescript equivalent of require('mytypescriptfile')(optionsObject); This is the TS code provided: export class Animal { name: string; public bark(): string { return "bark " + this.name; } constructor(color:string) ...