Lodash源码阅读-isPrototype

功能概述

isPrototype 函数是 Lodash 中用于检测一个值是否为某个对象的原型(prototype)的工具函数。它通过比较对象的构造函数的原型来判断,帮助我们识别一个对象是否是作为其他对象的原型。

源码实现

js 复制代码
function isPrototype(value) {
  var Ctor = value && value.constructor,
    proto = (typeof Ctor == "function" && Ctor.prototype) || objectProto;

  return value === proto;
}

实现原理解析

1. 获取构造函数

js 复制代码
var Ctor = value && value.constructor;

这行代码做了两件事:

  1. 首先通过 value && value.constructor 进行短路判断:
    • 如果 value 是 null 或 undefined,直接返回 null(短路)
    • 如果 value 有效,则获取其构造函数

示例:

js 复制代码
// 自定义类的情况
class Person {}
const personProto = Person.prototype;
console.log(personProto.constructor === Person); // true

// 内置对象的情况
const arrayProto = Array.prototype;
console.log(arrayProto.constructor === Array); // true

// null 的情况
const nullValue = null;
console.log(nullValue && nullValue.constructor); // null

2. 获取原型对象

js 复制代码
proto = (typeof Ctor == "function" && Ctor.prototype) || objectProto;

这行代码也很巧妙:

  1. 先判断 typeof Ctor == 'function'

    • 确保构造函数真的是个函数
    • 如果不是函数,这部分表达式返回 false
  2. 如果是函数,就获取 Ctor.prototype

    • 每个函数都有一个 prototype 属性
    • 这个属性指向该函数作为构造函数时的原型对象
  3. 如果前面都失败了,就用 objectProto(Object.prototype)作为后备:

    • 这确保了即使处理异常情况也有一个有效的原型对象

示例:

js 复制代码
// 自定义类的原型
class Animal {}
const animalProto = Animal.prototype;
console.log(Animal.prototype === animalProto); // true

// 内置对象的原型
console.log(Array.prototype === [].__proto__); // true
console.log(Object.prototype === {}.__proto__); // true

// 非函数构造器的情况
const obj = { constructor: 42 };
const proto =
  (typeof obj.constructor === "function" && obj.constructor.prototype) ||
  Object.prototype;
console.log(proto === Object.prototype); // true

3. 最终比较

js 复制代码
return value === proto;

这是最后的判断,使用严格相等(===)来比较:

  • 检查传入的 value 是否就是刚才获取到的原型对象
  • 使用 === 确保是同一个对象引用,而不是具有相同属性的不同对象

示例:

js 复制代码
// 检查是否是 Array 的原型
console.log(isPrototype(Array.prototype)); // true

// 检查普通对象是否是原型
const normalObj = { x: 1 };
console.log(isPrototype(normalObj)); // false

// 检查自定义类的原型
class MyClass {}
console.log(isPrototype(MyClass.prototype)); // true

// 特殊情况:Object.prototype
console.log(isPrototype(Object.prototype)); // true

注意事项

  1. 这个函数主要用于内部实现,一般用户代码很少直接使用
  2. 不要用这个函数来判断对象之间的继承关系,应该使用 instanceof 运算符
js 复制代码
// 错误的继承关系判断
class Animal {}
class Dog extends Animal {}

const dog = new Dog();
console.log(isPrototype(Animal.prototype)); // false,不能用这个判断 dog 是否继承自 Animal

// 正确的继承关系判断
console.log(dog instanceof Animal); // true,使用 instanceof 判断继承关系
console.log(Object.prototype.isPrototypeOf(dog)); // true,或使用 isPrototypeOf 方法
  1. 函数返回 true 的情况很少,因为一个对象要完全等于构造函数的 prototype 属性才行
js 复制代码
// 返回 true 的情况
console.log(isPrototype(Object.prototype)); // true
console.log(isPrototype(Array.prototype)); // true
console.log(isPrototype(Function.prototype)); // true

// 返回 false 的情况
const proto = { x: 1 };
function CustomClass() {}
CustomClass.prototype = proto;

console.log(isPrototype(new CustomClass())); // false,实例对象不是原型
console.log(isPrototype(proto)); // false,虽然是原型但不是构造函数直接的 prototype

// 特殊情况:Object.create(null) 创建的对象
const noProtoObj = Object.create(null);
console.log(isPrototype(noProtoObj)); // false,没有原型链的对象

总结

函数的判断逻辑是:

  1. 先获取这个对象的构造函数(value.constructor)
  2. 再获取构造函数的原型对象(constructor.prototype)
  3. 最后看传入的对象是否就是这个原型对象
相关推荐
2501_943782351 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq2 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net
吠品2 小时前
LangChain 里 tool_call_id 为空?一次 MCP 工具集成的排查记录
前端
柒和远方2 小时前
Phase 7.4 学习博客:为什么多 API 项目需要 Swagger / OpenAPI
前端·后端·架构
张龙6872 小时前
拼多多开放平台对接踩坑实录:从 CLIENT_ID 配置到 MD5 签名算法的完整填坑指南
前端
GuWenyue2 小时前
提示词彻底过时?一套上下文工程方案,3步让LLM落地生产,代码直接复用
前端·javascript·人工智能
柒和远方2 小时前
Phase 7.3 复盘:后台任务不只是“扔进队列”,还要能被看见
前端·后端·架构
2501_943782352 小时前
【共创季稿事节】 倒计时器:时分秒选择器与定时器的协同工作
前端·华为·harmonyos·鸿蒙·鸿蒙系统
奶油mm2 小时前
公司技术债堆积如山,我一人之力用 Vue3 偷换了整个前端架构
前端·vue.js
用户938515635072 小时前
深入理解 JavaScript 中的 this 与数据存储的奥秘
前端·javascript