【前端面试小册】JS-第32节:实现 instanceof

一、核心概念

1.1 instanceof 的作用

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

语法object instanceof constructor

返回值truefalse

1.2 基本使用

console.log([] instanceof Array);        // true
console.log({} instanceof Object);      // true
console.log([] instanceof Object);      // true
console.log(2 instanceof Number);       // false(基本类型)
console.log(new Number(2) instanceof Number);  // true

二、实现原理

2.1 基础实现

function myInstanceof(left, right) {
    let _left = left.__proto__;
    let _right = right.prototype;
    
    while (true) {
        if (_left === null) {
            return false;
        }
        if (_left === _right) {
            return true;
        }
        _left = _left.__proto__;
    }
}

2.2 原理解析

执行流程

graph TD
    A[调用 myInstanceof] --> B[获取 left 的 __proto__]
    B --> C[获取 right 的 prototype]
    C --> D{left.__proto__ === null?}
    D -->|是| E[返回 false]
    D -->|否| F{left.__proto__ === right.prototype?}
    F -->|是| G[返回 true]
    F -->|否| H[向上查找 __proto__]
    H --> D

关键点

  • 沿着 left 的原型链向上查找
  • 比较 left.__proto__right.prototype
  • 如果找到则返回 true,到达 null 则返回 false

2.3 执行示例

// 示例:[] instanceof Array
// 步骤 1: left = [], right = Array
// 步骤 2: _left = [].__proto__ = Array.prototype
// 步骤 3: _right = Array.prototype
// 步骤 4: _left === _right,返回 true

// 示例:[] instanceof Object
// 步骤 1: left = [], right = Object
// 步骤 2: _left = [].__proto__ = Array.prototype
// 步骤 3: _right = Object.prototype
// 步骤 4: _left !== _right,继续向上
// 步骤 5: _left = Array.prototype.__proto__ = Object.prototype
// 步骤 6: _left === _right,返回 true

三、优化版本

3.1 添加参数验证

function myInstanceof(left, right) {
    // 参数验证
    if (left === null || left === undefined) {
        return false;
    }
    
    if (typeof right !== 'function') {
        throw new TypeError('Right-hand side of instanceof is not callable');
    }
    
    let _left = left.__proto__;
    let _right = right.prototype;
    
    while (true) {
        if (_left === null) {
            return false;
        }
        if (_left === _right) {
            return true;
        }
        _left = _left.__proto__;
    }
}

3.2 使用 Object.getPrototypeOf

function myInstanceof(left, right) {
    if (left === null || left === undefined) {
        return false;
    }
    
    if (typeof right !== 'function') {
        throw new TypeError('Right-hand side of instanceof is not callable');
    }
    
    let proto = Object.getPrototypeOf(left);
    const prototype = right.prototype;
    
    while (proto !== null) {
        if (proto === prototype) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }
    
    return false;
}

优点

  • 使用标准 API Object.getPrototypeOf
  • 不依赖 __proto__(非标准属性)

3.3 完整版本

function myInstanceof(left, right) {
    // 基本类型直接返回 false
    if (left === null || left === undefined) {
        return false;
    }
    
    // right 必须是函数
    if (typeof right !== 'function') {
        throw new TypeError('Right-hand side of instanceof is not callable');
    }
    
    // 基本类型的包装对象需要特殊处理
    if (typeof left !== 'object' && typeof left !== 'function') {
        return false;
    }
    
    // 沿着原型链向上查找
    let proto = Object.getPrototypeOf(left);
    const prototype = right.prototype;
    
    while (proto !== null) {
        if (proto === prototype) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }
    
    return false;
}

四、测试用例

4.1 基础测试

// 测试 1:数组
const res = myInstanceof([], Array);
console.log(res);  // true

// 测试 2:对象
const res1 = myInstanceof({}, Object);
console.log(res1);  // true

// 测试 3:数组是 Object 的实例
const res2 = myInstanceof([], Object);
console.log(res2);  // true

// 测试 4:基本类型
const res3 = myInstanceof(2, Number);
console.log(res3);  // false

4.2 复杂测试

// 测试 5:自定义类
class Person {}
class Student extends Person {}

const student = new Student();
console.log(myInstanceof(student, Student));  // true
console.log(myInstanceof(student, Person));    // true
console.log(myInstanceof(student, Object));    // true

// 测试 6:函数
function fn() {}
console.log(myInstanceof(fn, Function));      // true
console.log(myInstanceof(fn, Object));        // true

// 测试 7:Date
const date = new Date();
console.log(myInstanceof(date, Date));        // true
console.log(myInstanceof(date, Object));      // true

// 测试 8:RegExp
const regex = /test/;
console.log(myInstanceof(regex, RegExp));     // true

4.3 边界情况

// 测试 9:null 和 undefined
console.log(myInstanceof(null, Object));      // false
console.log(myInstanceof(undefined, Object)); // false

// 测试 10:基本类型
console.log(myInstanceof('string', String));  // false
console.log(myInstanceof(true, Boolean));     // false

// 测试 11:包装对象
console.log(myInstanceof(new String(''), String));  // true
console.log(myInstanceof(new Number(2), Number));  // true

五、与原生的区别

5.1 行为一致性

// 原生 instanceof
console.log([] instanceof Array);        // true
console.log({} instanceof Object);      // true

// 我们的实现
console.log(myInstanceof([], Array));    // true
console.log(myInstanceof({}, Object));  // true

5.2 错误处理

// 原生 instanceof
try {
    [] instanceof null;
} catch (e) {
    console.log(e.message);  // Right-hand side of instanceof is not callable
}

// 我们的实现也应该抛出相同的错误
try {
    myInstanceof([], null);
} catch (e) {
    console.log(e.message);  // Right-hand side of instanceof is not callable
}

六、实际应用场景

6.1 类型检查

function processData(data) {
    if (myInstanceof(data, Array)) {
        return data.map(item => processItem(item));
    }
    
    if (myInstanceof(data, Object)) {
        return Object.keys(data).reduce((acc, key) => {
            acc[key] = processData(data[key]);
            return acc;
        }, {});
    }
    
    return data;
}

6.2 参数验证

function createUser(userData) {
    if (!myInstanceof(userData, Object)) {
        throw new TypeError('userData must be an object');
    }
    
    if (!myInstanceof(userData.name, String)) {
        throw new TypeError('userData.name must be a string');
    }
    
    // 创建用户
    return new User(userData);
}

七、面试要点总结

核心知识点

  1. instanceof 原理:沿着原型链向上查找
  2. 实现方式:循环比较 __proto__prototype
  3. 边界情况:null、undefined、基本类型
  4. 标准 API:使用 Object.getPrototypeOf 更规范

常见面试题

Q1: 如何实现 instanceof?

答:沿着对象的原型链向上查找,比较 __proto__ 和构造函数的 prototype,如果找到则返回 true,到达 null 则返回 false

Q2: instanceof 和 typeof 的区别?

答:

  • typeof:返回基本类型字符串,无法区分对象类型
  • instanceof:判断对象是否为某个构造函数的实例,可以判断对象类型

Q3: 为什么基本类型 instanceof 返回 false?

答:instanceof 检查的是对象,基本类型不是对象,所以返回 false。需要使用包装对象(如 new Number(2))才能返回 true

实战建议

  • ✅ 理解原型链的查找机制
  • ✅ 掌握 __proto__prototype 的关系
  • ✅ 注意边界情况的处理
  • ✅ 使用标准 API Object.getPrototypeOf
#前端面试##银行##百度##滴滴##腾讯#
前端面试小册 文章被收录于专栏

每天更新3-4节,持续更新中... 目标:50天学完,上岸银行总行!

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务