stevecreswick
stevecreswick

Reputation: 101

Why does instanceof a class return false even though the constructor is in its prototype chain?

In a NodeJS app, I am trying to check that a value passed into a function is an instance of a specific Class, however I am getting unexpected behavior using instanceof between modules, and when checking the equality of the Class.

endpoint.js

import SomeClass from 'utils/class';
import SomeModel from 'models/model';

const model = SomeModel.findOne({id: 'abc'});
const values = {a: 'b'};
const classInstance = new SomeClass({id: 'def'});

classInstance instanceof SomeClass //returns true
Object.getPrototypeOf(classInstance) //returns SomeClass {}

model.update(values, { a: classInstance, b: SomeClass });

When the classInstance is passed through to the update function, I see unexpected behavior.

Calling Object.getPrototypeOf(a) returns SomeClass, as does a.constructor.name. However, a instanceof SomeClass returns false.

Furthermore, just checking equality between the class imported and the class passed into the function returns false.

require.resolve('utils/class') returns the same path for both imports.

models/model.js

import SomeClass from 'utils/class';

class Model {
  async update(values, injections) {
    const { a, b } = injections;

    // checking instance
    a.constructor.name //returns SomeClass
    Object.getPrototypeOf(a) //returns SomeClass {}
    a instanceof SomeClass; //returns false

    // checking class
    b === SomeClass; //returns false
  }
}

I would expect that b === SomeClass would return true, just like a instanceof SomeClass should also return true, unless I am missing something. Thanks for any help.

utils/class.js

export default class SomeClass {
  constructor(foo) {
    this.bar = foo;
  }
}

Edit: The code is being transpiled with @std/esm. NODE_PATH=./src/ nodemon -r @std/esm src/server.js

Upvotes: 10

Views: 1718

Answers (2)

Dave Stein
Dave Stein

Reputation: 9326

Charlie in the comments pointed us the right way.

https://github.com/DaveStein/esm-bug is reproducing this and I've noted it as such in the issue Charlie reported https://github.com/standard-things/esm/issues/633.

Upvotes: 2

Charlie Schliesser
Charlie Schliesser

Reputation: 8246

Is it due to the SomeClass instances being defined multiple times (due to transpiler, etc)? Consider this code which will return false:

(function() {

    class Foo {};

    class Bar {
        check(a) {
            console.log(a instanceof Foo);
        }
    };

    window.bar = new Bar();

})();

(function() {
    class Foo {};
    const foo = new Foo();
    window.bar.check(foo);
})();

vs Foo, Bar, etc., being defined in a global scope only 1 time (require() should cache these dependencies and thus you shouldn't run into this behavior):

class Foo {};

class Bar {
    check(a) {
        console.log(a instanceof Foo);
    }
};

const foo = new Foo();
Bar.prototype.check(foo);

There's an issue on the std/esm project where someone's experiencing this same thing. I don't use that library, so no ideas on the specifics.

Or I could be way off.

Upvotes: 2

Related Questions