Skip to the code
cf.

The instanceof operator

Write myInstanceOf(value, Constructor), which returns what value instanceof Constructor would: true if Constructor.prototype appears anywhere in value's prototype chain, false if the chain ends (at null) without meeting it. Walk the chain yourself with Object.getPrototypeOf; don't use instanceof or isPrototypeOf.

Primitives such as 1 or "text" have no prototype chain of their own, so they give false, and so do null and undefined.

Like the operator, throw a TypeError if Constructor isn't a function, or if value is an object and Constructor.prototype isn't one (arrow functions have no prototype). Use only the prototype chain: a class that customizes Symbol.hasInstance doesn't change your answer.

class Animal {}
class Dog extends Animal {}
const rex = new Dog();
myInstanceOf(rex, Dog);    // true
myInstanceOf(rex, Animal); // true
myInstanceOf(rex, Object); // true
myInstanceOf(rex, Array);  // false
myInstanceOf(1, Number);   // false

What the tests check

  1. is true for an instance of the constructor
    function Person() {}
    const ada = new Person();
    expect(myInstanceOf(ada, Person)).toBe(true);
    expect(myInstanceOf([], Array)).toBe(true);
    
  2. walks up the whole prototype chain
    class Animal {}
    class Dog extends Animal {}
    const rex = new Dog();
    expect(myInstanceOf(rex, Animal)).toBe(true);
    expect(myInstanceOf(rex, Object)).toBe(true);
    
  3. is false when the prototype isn't in the chain
    class Animal {}
    class Dog extends Animal {}
    expect(myInstanceOf(new Animal(), Dog)).toBe(false);
    expect(myInstanceOf(new Dog(), Array)).toBe(false);
    expect(myInstanceOf({}, Dog)).toBe(false);
    
  4. is false for primitives, even when Constructor has no prototype
    expect(myInstanceOf(1, Number)).toBe(false);
    expect(myInstanceOf("text", String)).toBe(false);
    expect(myInstanceOf(true, Boolean)).toBe(false);
    expect(myInstanceOf(1, () => {})).toBe(false);
    
  5. is false for null, undefined, and objects with no prototype
    expect(myInstanceOf(null, Object)).toBe(false);
    expect(myInstanceOf(undefined, Object)).toBe(false);
    expect(myInstanceOf(Object.create(null), Object)).toBe(false);
    
  6. throws a TypeError when Constructor can't be checked
    expect(() => myInstanceOf({}, {})).toThrow(TypeError);
    expect(() => myInstanceOf({}, "Object")).toThrow(TypeError);
    expect(() => myInstanceOf({}, () => {})).toThrow(TypeError);
    
  7. ignores a custom Symbol.hasInstance
    class Anything {
      static [Symbol.hasInstance]() {
        return true;
      }
    }
    expect(myInstanceOf({}, Anything)).toBe(false);
    expect(myInstanceOf(new Anything(), Anything)).toBe(true);
    
  8. walks the chain itself, without isPrototypeOf
    const builtIn = Object.prototype.isPrototypeOf;
    Object.prototype.isPrototypeOf = function () {
      throw new Error("myInstanceOf called isPrototypeOf");
    };
    let found;
    try {
      found = myInstanceOf([], Object);
    } finally {
      Object.prototype.isPrototypeOf = builtIn;
    }
    expect(found).toBe(true);
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).