【前端面试小册】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天学完,上岸银行总行!

全部评论

相关推荐

11-16 18:30
已编辑
华南理工大学 Java
一、背景介绍本人是27届本科,目前在🐧实习,目前对于实习段数,简历拷打,学习建议有一些问题咨询,目标冲刺明年的sp(大佬勿喷,个人的目标,不一定实现,多多担待),但也在纠结是否考研实习组内情况缺点:1.组里是b端业务,流量不大,更多的做的是一些b端定制化需求2.组内技术栈和本人技术栈不对口(这个其实我不太重视,感觉语言不太重要,但写着确实难受)3.业务流程不太好,不像大厂的规范,产品大多数只给需求和拉群,不怎么提前对一下,导致给了需求有时候不知道怎么写,开发效率低,经常问正职,总的来说landing熟悉项目给的时间少,开发流程规范不好优点1.Dw 比较少,实习生做正式工的活,之前挺闲的,最近组里开始非常忙2.正直都挺好,但是都挺忙3.能学到东西,但感觉总一个人搞,效率低我之前在美团实习过一段,避免开盒把组隐藏了。第一个组干了两个月,产出基本只有第一个和第二个,别的都是包的。第二个组产出是自己做的,业务看着牛逼,但是很简单,都是封装好的,什么短链接、短信通知都是封装好的sdk,直接调用就🉑(大厂是这样的,都是复用之前写好的….)腾讯产出也很简单,用ai润色了一下,把产出大概写上了(很多都是dw,后面会删掉,这Ai 润色的太高大上了…..)而且个人在大模型时代热潮的冲击下,也有想要尝试学习和接触AI大模型的想法,萌生了考研的想法(30%的意愿吧),当然也了解并不是读了研就能搞算法,但感觉研究生的选择相对来说还是更多一些。所以有必要读研,选择更多一些呢?不知道大家对于大模型LLM发展与就业场景、大模型时代下开发未来发展前景(总有感觉会被替代,至少会被疯狂冲)想法如何,希望可以一块交流一下二、问题1️⃣我想着1月份还需要再找一段吗?有同学说质量+时长最重要,有同学说3个月+段数最重要…但感觉有些拿到ssp的确实段数非常多…1. 1月份找一段,再沉淀一段2.直接实习到明年暑期开,边实习边沉淀,暑期开了投递2️⃣顺便咨询一下大佬们的学习建议1.拓展一下技术栈,尝试学习Ai agent类似的热门方向2.尝试搞一下开源3.多读后端技术文章,一直强化八股4.学习国外公开课,做lab projs3️⃣简历修改建议个人觉得有一些产出包的过于夸张,希望大佬指正修改4️⃣就业 or 考研如上
淬月星辉:不用了吧,秋招筹码够大了
投递大连飞创信息技术有限公司等公司10个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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