说说instanceof和typeof的实现原理并自己模拟实现一个instanceof
Let's break down the typeof and instanceof operators in JavaScript and then create a custom instanceof implementation.
typeof Operator
-
Implementation Principle: The
typeofoperator determines the primitive type of a value. It's a unary operator (takes one operand) and returns a string indicating the type. Internally, it checks the internal [[Type]] property of the value. This property isn't directly accessible to JavaScript code, buttypeofprovides a way to query it. -
Limitations:
typeofis primarily useful for primitive types. For objects (including arrays and functions), it usually returns "object," except for functions where it returns "function." This makes it less helpful for distinguishing between different object types.typeof nullnotoriously returns "object," which is a historical bug.
instanceof Operator
-
Implementation Principle: The
instanceofoperator checks if an object is an instance of a particular constructor (or a constructor in its prototype chain). It works by traversing the prototype chain of the object. If it encounters a prototype that matches the constructor's prototype, it returnstrue. Otherwise, if it reaches the end of the prototype chain without a match, it returnsfalse. -
How it works with prototypes: Every object in JavaScript has a prototype (accessible via
__proto__orObject.getPrototypeOf()). When you create an object using a constructor function (e.g.,new MyClass()), the object's prototype is set to the constructor'sprototypeproperty.instanceofleverages this relationship to determine inheritance.
Custom instanceof Implementation
function myInstanceof(obj, constructor) {
if (obj === null || typeof obj !== 'object') {
return false; // null and non-objects are not instances of anything
}
let proto = Object.getPrototypeOf(obj);
while (proto) {
if (proto === constructor.prototype) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
return false; // Reached end of prototype chain without a match
}
// Example usage:
function MyClass() {}
const myObj = new MyClass();
console.log(myInstanceof(myObj, MyClass)); // true
console.log(myInstanceof({}, Object)); // true
console.log(myInstanceof([], Array)); // true
console.log(myInstanceof([], Object)); // true (Arrays inherit from Object)
console.log(myInstanceof(null, Object)); // false (Handles the null case)
console.log(myInstanceof(5, Number)); // false (Handles primitives)
console.log(myInstanceof(myObj, Array)); // false
// Demonstrating with a more complex prototype chain
function Parent() {}
function Child() {}
Child.prototype = Object.create(Parent.prototype);
const childObj = new Child();
console.log(myInstanceof(childObj, Child)); // true
console.log(myInstanceof(childObj, Parent)); // true (Inheritance)
Key improvements in the custom implementation:
- Handles
nullcorrectly: Explicitly checks fornulland returnsfalse. - Handles non-objects: Checks if the left-hand operand is an object. If not, it returns
false. This prevents errors when used with primitives. - Uses
Object.getPrototypeOf(): This is the preferred way to access the prototype. While__proto__works, it's deprecated for general use.
This custom implementation closely mirrors the behavior of the built-in instanceof operator, providing a clearer understanding of its underlying mechanism. Remember that built-in operators are generally optimized, so in performance-critical scenarios, using the native instanceof is recommended. However, for understanding and learning, building a custom version is extremely valuable.
浙公网安备 33010602011771号