Search code examples
javascriptecmascript-6prototypeinstanceof

Why does setting the prototype of an object to `Foo` not make it `instanceof Foo`?


I am trying to use Object.setPrototypeOf to re-set the prototype of objects that have been converted to JSON and back into an object. However, instanceof doesn't seem to work the way I'd expect:

class Foo {}

const obj = {};
Object.setPrototypeOf(obj, Foo);
console.log(obj instanceof Foo);

Why is this the case? To my knowledge instanceof works based on comparing the prototype of a given object to the referenced class. Is there a different way this should be done?


Solution

  • JS classes are just syntactic sugar for constructor functions and prototypes. Foo is the constructor function, not the prototype...so you'd need to use Foo.prototype and not Foo:

    Object.setPrototypeOf({ }, Foo.prototype)
    

    However, I wouldn't recommend this approach for your use case due to this warning on MDN:

    Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation

    Instead, use Object.create():

    const obj = Object.create(Foo.prototype)
    

    You can then use Object.assign() to copy the data (assuming that data is your parsed JSON data):

    Object.assign(obj, data)
    

    Alternatively, if your class has a constructor that allows you to set its initial state from an argument, you could just use new Foo(data), but the above approach is more generic since it bypasses the constructor.