2618. Check if Object Instance of Class
Problem Description
This problem asks you to implement a function checkIfInstanceOf
that determines whether a given value is an instance of a specified class or any of its superclasses.
The function takes two parameters:
obj
: any value that needs to be checkedclassFunction
: a class or constructor function to check against
The function should return true
if the object is an instance of the given class or inherits from it through the prototype chain. An object is considered an instance if it has access to that class's methods through prototypal inheritance.
Key requirements:
- The function must handle edge cases where either parameter could be
null
orundefined
- There are no restrictions on data types - any JavaScript value can be passed as either parameter
- The check should work for built-in classes (like
Date
,Array
) as well as custom classes - The function needs to traverse the entire prototype chain to check for inheritance relationships
For example:
checkIfInstanceOf(new Date(), Date)
should returntrue
because the object is a direct instance ofDate
checkIfInstanceOf([], Object)
should returntrue
because arrays inherit fromObject
checkIfInstanceOf(5, Number)
should returnfalse
because primitive numbers don't haveNumber.prototype
in their prototype chain- If
classFunction
isnull
orundefined
, the function should returnfalse
Intuition
The key insight is understanding how JavaScript's prototype chain works. Every object in JavaScript (except for primitive values) has an internal link to another object called its prototype. When we create an instance of a class using new
, the created object's prototype points to the class's prototype
property.
To check if an object is an instance of a class, we need to walk up the prototype chain and see if we ever encounter the class's prototype. Think of it like climbing a family tree - if we start from a person and keep going to their parent, grandparent, and so on, we can determine if they're descended from a particular ancestor.
The approach becomes clear when we consider:
- Direct instances have their immediate prototype equal to
classFunction.prototype
- Inherited instances have
classFunction.prototype
somewhere higher up in their prototype chain - We need to handle edge cases where the class itself might be
null
orundefined
The solution uses Object.getPrototypeOf()
to traverse the chain step by step. Starting from the object, we check if its prototype matches the class's prototype. If not, we move up to the next level (the prototype's prototype) and check again. We continue this process until either:
- We find a match (return
true
) - We reach the end of the chain (
null
orundefined
), meaning no inheritance relationship exists (returnfalse
)
This approach naturally handles both direct instantiation and inheritance through subclasses, as both cases result in the parent class's prototype appearing somewhere in the chain.
Solution Approach
The implementation follows a straightforward prototype chain traversal algorithm:
-
Initial Validation: First, we check if
classFunction
isnull
orundefined
. If it is, we immediately returnfalse
since there's no valid class to check against. -
Prototype Chain Traversal: We use a
while
loop to walk up the prototype chain:while (obj !== null && obj !== undefined) { const proto = Object.getPrototypeOf(obj); if (proto === classFunction.prototype) { return true; } obj = proto; }
-
Step-by-step Process:
- Start with the given object
obj
- Get its prototype using
Object.getPrototypeOf(obj)
- Compare this prototype with
classFunction.prototype
- If they match, we've found the class in the inheritance chain - return
true
- If not, move up the chain by setting
obj = proto
and repeat
- Start with the given object
-
Termination Conditions:
- Success: We find a prototype that matches
classFunction.prototype
- Failure: We reach the end of the chain (when
obj
becomesnull
orundefined
)
- Success: We find a prototype that matches
-
Edge Case Handling:
- Primitive values (like numbers, strings) when boxed will have prototypes that can be traversed
null
andundefined
values forobj
will cause the loop to skip entirely and returnfalse
- Invalid
classFunction
values are caught at the beginning
The algorithm has a time complexity of O(n)
where n
is the depth of the prototype chain, and space complexity of O(1)
as we only use a constant amount of extra space for the proto
variable.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to understand how the solution works. Consider checking if a custom Dog
instance is an instance of Animal
:
class Animal {}
class Dog extends Animal {}
const myDog = new Dog();
// Check: checkIfInstanceOf(myDog, Animal)
Step-by-step execution:
-
Initial Validation:
classFunction
(Animal) is notnull
orundefined
✓- Continue to prototype chain traversal
-
First Iteration:
obj = myDog
(not null/undefined, so enter loop)proto = Object.getPrototypeOf(myDog)
→ getsDog.prototype
- Compare:
Dog.prototype === Animal.prototype
? → No - Update:
obj = Dog.prototype
-
Second Iteration:
obj = Dog.prototype
(not null/undefined, continue)proto = Object.getPrototypeOf(Dog.prototype)
→ getsAnimal.prototype
- Compare:
Animal.prototype === Animal.prototype
? → Yes! - Return
true
The function correctly identifies that myDog
is an instance of Animal
by finding Animal.prototype
in the prototype chain.
Contrast with a failing case:
checkIfInstanceOf(5, Number)
- Initial Validation:
Number
is valid ✓ - First Iteration:
obj = 5
(primitive, but not null/undefined)proto = Object.getPrototypeOf(5)
→ getsNumber.prototype
(via boxing)- Compare:
Number.prototype === Number.prototype
? → Wait, this should be true!
Actually, let me reconsider this example. When we call Object.getPrototypeOf(5)
, JavaScript boxes the primitive to a Number
object temporarily. However, the primitive 5
itself doesn't have Number.prototype
in its chain the way an object created with new Number(5)
would.
Let's use a clearer failing example:
checkIfInstanceOf([], Date)
-
Initial Validation:
Date
is valid ✓ -
First Iteration:
obj = []
(array, not null/undefined)proto = Object.getPrototypeOf([])
→ getsArray.prototype
- Compare:
Array.prototype === Date.prototype
? → No - Update:
obj = Array.prototype
-
Second Iteration:
obj = Array.prototype
(not null/undefined)proto = Object.getPrototypeOf(Array.prototype)
→ getsObject.prototype
- Compare:
Object.prototype === Date.prototype
? → No - Update:
obj = Object.prototype
-
Third Iteration:
obj = Object.prototype
(not null/undefined)proto = Object.getPrototypeOf(Object.prototype)
→ getsnull
- Compare:
null === Date.prototype
? → No - Update:
obj = null
-
Fourth Iteration Check:
obj = null
→ exit loop- Return
false
The array is not an instance of Date
because Date.prototype
never appears in its prototype chain.
Solution Implementation
1def checkIfInstanceOf(obj, classFunction):
2 """
3 Checks if an object is an instance of a given class/constructor function
4 by traversing the prototype chain.
5
6 Args:
7 obj: The object to check
8 classFunction: The constructor function/class to check against
9
10 Returns:
11 bool: True if obj is an instance of classFunction, False otherwise
12 """
13 # Handle edge cases where classFunction is None
14 if classFunction is None:
15 return False
16
17 # In Python, we check instance relationship using isinstance() or type checking
18 # For primitive types, we need special handling
19 if obj is None:
20 return False
21
22 # Direct instance check using isinstance
23 try:
24 # Handle primitive types that need special treatment
25 if classFunction == str and isinstance(obj, str):
26 return True
27 elif classFunction == int and isinstance(obj, int) and not isinstance(obj, bool):
28 return True
29 elif classFunction == float and isinstance(obj, (int, float)) and not isinstance(obj, bool):
30 return True
31 elif classFunction == bool and isinstance(obj, bool):
32 return True
33 elif classFunction == list and isinstance(obj, list):
34 return True
35 elif classFunction == dict and isinstance(obj, dict):
36 return True
37 elif classFunction == tuple and isinstance(obj, tuple):
38 return True
39 elif classFunction == set and isinstance(obj, set):
40 return True
41 # For custom classes and built-in types, use isinstance
42 elif isinstance(obj, classFunction):
43 return True
44 # Check if obj's type is a subclass of classFunction
45 elif isinstance(type(obj), type) and issubclass(type(obj), classFunction):
46 return True
47 except (TypeError, AttributeError):
48 # If classFunction is not a valid type/class, return False
49 return False
50
51 # No match found
52 return False
53
54
55# Example usage:
56# from datetime import datetime
57# checkIfInstanceOf(datetime.now(), datetime) # True
58# checkIfInstanceOf("hello", str) # True
59# checkIfInstanceOf(5, int) # True
60# checkIfInstanceOf(None, list) # False
61# checkIfInstanceOf([], object) # True
62
1/**
2 * Checks if an object is an instance of a given class/constructor function
3 * by traversing the inheritance chain.
4 *
5 * @param obj - The object to check
6 * @param classFunction - The class to check against
7 * @return true if obj is an instance of classFunction, false otherwise
8 */
9public static boolean checkIfInstanceOf(Object obj, Class<?> classFunction) {
10 // Handle edge cases where classFunction is null
11 if (classFunction == null) {
12 return false;
13 }
14
15 // Handle null object case
16 if (obj == null) {
17 return false;
18 }
19
20 // Get the class of the object
21 Class<?> currentClass = obj.getClass();
22
23 // Traverse the inheritance chain of the object
24 while (currentClass != null) {
25 // Check if the current class matches the target class
26 if (currentClass.equals(classFunction)) {
27 return true;
28 }
29
30 // Check interfaces implemented by the current class
31 Class<?>[] interfaces = currentClass.getInterfaces();
32 for (Class<?> iface : interfaces) {
33 if (iface.equals(classFunction)) {
34 return true;
35 }
36 // Recursively check parent interfaces
37 if (checkInterfaceHierarchy(iface, classFunction)) {
38 return true;
39 }
40 }
41
42 // Move up the inheritance chain to the superclass
43 currentClass = currentClass.getSuperclass();
44 }
45
46 // No match found in the inheritance chain
47 return false;
48}
49
50/**
51 * Helper method to check interface hierarchy recursively
52 *
53 * @param iface - The interface to check
54 * @param targetClass - The target class to match against
55 * @return true if targetClass is found in the interface hierarchy
56 */
57private static boolean checkInterfaceHierarchy(Class<?> iface, Class<?> targetClass) {
58 // Get parent interfaces of the current interface
59 Class<?>[] parentInterfaces = iface.getInterfaces();
60
61 // Check each parent interface
62 for (Class<?> parentInterface : parentInterfaces) {
63 if (parentInterface.equals(targetClass)) {
64 return true;
65 }
66 // Recursively check the parent interface's hierarchy
67 if (checkInterfaceHierarchy(parentInterface, targetClass)) {
68 return true;
69 }
70 }
71
72 return false;
73}
74
75/**
76 * Example usage:
77 * checkIfInstanceOf(new Date(), Date.class); // true
78 * checkIfInstanceOf("hello", String.class); // true
79 * checkIfInstanceOf(5, Integer.class); // true (autoboxed)
80 * checkIfInstanceOf(null, ArrayList.class); // false
81 * checkIfInstanceOf(new ArrayList<>(), List.class); // true
82 */
83
1#include <typeinfo>
2#include <type_traits>
3
4/**
5 * Checks if an object is an instance of a given class/type
6 * by using C++ RTTI (Run-Time Type Information).
7 *
8 * Note: C++ doesn't have prototype chains like JavaScript.
9 * This implementation uses dynamic_cast for polymorphic types
10 * and type traits for primitive types.
11 *
12 * @tparam T - The type of the object to check
13 * @tparam ClassType - The class/type to check against
14 * @param obj - Pointer to the object to check
15 * @returns true if obj is an instance of ClassType, false otherwise
16 */
17template<typename ClassType, typename T>
18bool checkIfInstanceOf(T* obj) {
19 // Handle null pointer case
20 if (obj == nullptr) {
21 return false;
22 }
23
24 // For polymorphic types, use dynamic_cast
25 // dynamic_cast returns nullptr if the cast fails
26 if constexpr (std::is_polymorphic_v<T> && std::is_polymorphic_v<ClassType>) {
27 return dynamic_cast<ClassType*>(obj) != nullptr;
28 }
29 // For non-polymorphic types, use compile-time type checking
30 else {
31 return std::is_base_of_v<ClassType, T> || std::is_same_v<ClassType, T>;
32 }
33}
34
35/**
36 * Overload for checking primitive types and values
37 *
38 * @tparam T - The type to check
39 * @tparam ClassType - The type to check against
40 * @param obj - The object value (by reference)
41 * @returns true if obj is of type ClassType, false otherwise
42 */
43template<typename ClassType, typename T>
44bool checkIfInstanceOf(const T& obj) {
45 // Use type traits to check if types match
46 return std::is_same_v<std::decay_t<T>, ClassType>;
47}
48
49/**
50 * Example usage:
51 *
52 * class Base { virtual ~Base() {} };
53 * class Derived : public Base {};
54 *
55 * Derived d;
56 * Base* b = &d;
57 *
58 * checkIfInstanceOf<Base>(&d); // true
59 * checkIfInstanceOf<Derived>(b); // true
60 * checkIfInstanceOf<int>(5); // true
61 * checkIfInstanceOf<double>(5); // false
62 * checkIfInstanceOf<Base>(nullptr); // false
63 */
64
1/**
2 * Checks if an object is an instance of a given class/constructor function
3 * by traversing the prototype chain.
4 *
5 * @param obj - The object to check
6 * @param classFunction - The constructor function/class to check against
7 * @returns true if obj is an instance of classFunction, false otherwise
8 */
9function checkIfInstanceOf(obj: any, classFunction: any): boolean {
10 // Handle edge cases where classFunction is null or undefined
11 if (classFunction === null || classFunction === undefined) {
12 return false;
13 }
14
15 // Traverse the prototype chain of the object
16 while (obj !== null && obj !== undefined) {
17 // Get the prototype of the current object
18 const proto: any = Object.getPrototypeOf(obj);
19
20 // Check if the prototype matches the classFunction's prototype
21 if (proto === classFunction.prototype) {
22 return true;
23 }
24
25 // Move up the prototype chain
26 obj = proto;
27 }
28
29 // No match found in the prototype chain
30 return false;
31}
32
33/**
34 * Example usage:
35 * checkIfInstanceOf(new Date(), Date); // true
36 * checkIfInstanceOf("hello", String); // true
37 * checkIfInstanceOf(5, Number); // true
38 * checkIfInstanceOf(null, Array); // false
39 * checkIfInstanceOf([], Object); // true
40 */
41
Time and Space Complexity
Time Complexity: O(n)
where n
is the depth of the prototype chain from the object to its root prototype (null).
The function traverses the prototype chain using a while loop, starting from the given object and moving up through each prototype level using Object.getPrototypeOf()
. In the worst case, it needs to traverse the entire prototype chain until reaching null
. Each iteration performs constant time operations: getting the prototype (O(1)
) and comparing it with classFunction.prototype
(O(1)
).
Space Complexity: O(1)
- constant space complexity.
The function only uses a fixed amount of extra space regardless of the input size. It reuses the same variable obj
to traverse the prototype chain and uses a single variable proto
to store the current prototype. No additional data structures that grow with input size are created, and the function doesn't use recursion (which would create a call stack proportional to the prototype chain depth).
Common Pitfalls
1. Confusing JavaScript Prototype Chain with Python's Type System
The provided Python solution doesn't accurately implement the JavaScript prototype chain traversal logic. Python uses a different inheritance model based on classes and metaclasses, not prototypes. The solution attempts to map JavaScript behavior to Python, but this creates several issues:
Problem:
# This Python code doesn't actually traverse a prototype chain
if isinstance(obj, classFunction):
return True
Better Approach:
def checkIfInstanceOf(obj, classFunction):
if classFunction is None:
return False
if obj is None:
return False
# Use Python's MRO (Method Resolution Order) to simulate prototype chain
obj_type = type(obj)
# Check direct instance
if obj_type == classFunction:
return True
# Traverse the inheritance hierarchy using __mro__
for base_class in obj_type.__mro__:
if base_class == classFunction:
return True
return False
2. Incorrect Handling of Primitive Types
The solution has redundant and incorrect handling of primitive types. In JavaScript, primitives like 5
don't have Number.prototype
in their chain, but the Python code treats them as instances:
Problem:
elif classFunction == int and isinstance(obj, int):
return True # This would return True for checkIfInstanceOf(5, int)
Correct Behavior (JavaScript-aligned):
def checkIfInstanceOf(obj, classFunction):
# Primitives in JavaScript don't have prototypes in their chain
# Only their boxed versions do
if classFunction is None:
return False
# Check if obj is a primitive (not an object)
primitive_types = (int, float, str, bool, type(None))
if type(obj) in primitive_types:
# Primitives return false unless explicitly boxed
return False
# For objects, check the inheritance chain
return isinstance(obj, classFunction) if classFunction else False
3. Missing Prototype Chain Simulation
The original JavaScript solution traverses the prototype chain using Object.getPrototypeOf()
. The Python version doesn't simulate this behavior:
JavaScript-style Implementation in Python:
def checkIfInstanceOf(obj, classFunction):
if classFunction is None:
return False
if obj is None:
return False
# Simulate prototype chain traversal
current_class = obj.__class__
while current_class is not None:
if current_class == classFunction:
return True
# Move up the inheritance chain
bases = current_class.__bases__
if bases:
current_class = bases[0] # Follow first base class
else:
break
# Check if classFunction is 'object' (everything inherits from object in Python)
if classFunction == object and obj is not None:
return True
return False
4. Exception Handling Too Broad
The try-except block catches TypeError
and AttributeError
but doesn't distinguish between different error causes:
Problem:
except (TypeError, AttributeError): return False # Silently fails for all errors
Better Approach:
def checkIfInstanceOf(obj, classFunction):
if classFunction is None:
return False
if obj is None:
return False
# Check if classFunction is actually a class/type
if not isinstance(classFunction, type):
return False
try:
return isinstance(obj, classFunction)
except TypeError as e:
# Log or handle specific error cases
if "isinstance() arg 2" in str(e):
return False # classFunction is not a valid type
raise # Re-raise unexpected errors
5. Inconsistent Boolean Handling
The code treats bool
specially but bool
is a subclass of int
in Python, leading to potential confusion:
Problem:
elif classFunction == int and isinstance(obj, int) and not isinstance(obj, bool):
return True # Excludes booleans from int check
Clearer Approach:
def checkIfInstanceOf(obj, classFunction):
if classFunction is None or obj is None:
return False
# Handle bool/int relationship explicitly
if classFunction == int and isinstance(obj, bool):
# In Python, bool is a subclass of int
# Decide based on requirements
return True # or False, depending on specification
return isinstance(obj, classFunction)
Depth first search is equivalent to which of the tree traversal order?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!