Check JavaScript Prototype Ancestry
Company: Google
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Other
# Check JavaScript Prototype Ancestry
Implement `checkIfInstanceOf(obj, classFunction)`, returning a Boolean that reports whether a value has a specified prototype among its strict ancestors.
This is an ordinary prototype-chain exercise. Use the rules below; custom instance-check hooks do not determine the result.
### Rules
- Either argument may have any ordinary JavaScript value type, including `undefined`, `null`, Boolean, number, bigint, string, symbol, object, or function. Missing arguments are `undefined`.
- Return `false` if `obj` is `null` or `undefined`, or if `classFunction` is not a function.
- For a function argument, read `classFunction.prototype` using normal property lookup. If that value is `null` or is neither an object nor a function, return `false`. A bound function without a usable `.prototype` therefore returns `false`; do not substitute the bound target's prototype.
- Otherwise, use the object itself for an object or function value, and its standard boxed object for a primitive. Return `true` exactly when `classFunction.prototype` occurs among that object's strict prototype ancestors. The starting object is not its own ancestor. Return `false` if the chain ends without a match.
- Ignore `Symbol.hasInstance` hooks. Do not invoke a constructor or an instance method to determine the answer.
### Constraints and Clarifications
Assume conventional, unmodified JavaScript built-ins and ordinary objects/functions with finite, acyclic prototype chains. The `.prototype` lookup and each prototype lookup terminate, do not throw, and remain stable throughout the call. Proxies, exotic objects, accessor-driven prototype lookup, and lookup that mutates, throws, or does not terminate are outside this bounded exercise. There is no fixed numeric limit on chain depth.
The function name is retained, but the result is defined by prototype identity. Copying a method or changing a `constructor` property does not establish ancestry. The function argument need not support `new`: what matters is whether it is a function with a usable `.prototype`.
### Examples
```javascript
checkIfInstanceOf(new Date(), Date); // true
class Animal {}
class Dog extends Animal {}
checkIfInstanceOf(new Dog(), Animal); // true
checkIfInstanceOf(Date, Date); // false
checkIfInstanceOf(5, Number); // true
```
A date object has `Date.prototype` in its chain, and a dog object has `Animal.prototype` farther up its chain. The `Date` function itself does not have `Date.prototype` as an ancestor. Boxing `5` gives an object whose chain contains `Number.prototype`.
Additional cases under this exercise's rules:
```javascript
checkIfInstanceOf(undefined, Number); // false
checkIfInstanceOf(5, undefined); // false
checkIfInstanceOf(null, Object); // false
checkIfInstanceOf({}, {}); // false
checkIfInstanceOf(Object.create(null), Object); // false
checkIfInstanceOf(Number.prototype, Number); // false
checkIfInstanceOf(true, Boolean); // true
checkIfInstanceOf(1n, BigInt); // true
checkIfInstanceOf(Symbol("x"), Symbol); // true
checkIfInstanceOf({}, () => {}); // false
```
```hint Identify the relationship
An object's own properties can resemble another object's properties without giving the two objects the same ancestors.
```
### What a Strong Answer Covers
- The return values for nullish values, nonfunction class arguments, and functions without a usable prototype.
- Primitive boxing and strict prototype identity, including why the starting object does not count as an ancestor.
- Superclass membership and cases where a `constructor` property, method names, or instance-check hooks disagree with actual prototype ancestry.
- Time and auxiliary-space costs in terms of the prototype-chain length.
### Follow-up Questions
- Why can copying a method from `Animal.prototype` onto an unrelated object leave the result `false`?
- Why does `checkIfInstanceOf(5, Number)` differ from `5 instanceof Number`, and why would using `instanceof` also conflict with the hook rule?
Overview: Practice JavaScript prototype ancestry with primitive boxing, superclass chains, and invalid arguments in a bounded checkIfInstanceOf exercise.