应逐字段比对属性描述符,先判类型(数据/访问器),再分别比对对应字段;函数引用用===,不可用深比较;批量比较需确保属性名完全一致。

直接比较两个对象的属性描述符,不能用 === 或 JSON.stringify,因为描述符是对象,引用不同就判为不等;关键在于逐字段比对其可枚举性、可配置性、可写性、值或 getter/setter 等核心字段。
提取并标准化描述符再比较
使用 Object.getOwnPropertyDescriptor(obj, prop) 获取描述符后,需注意:描述符可能只含部分字段(如只有 value 和 writable,不含 get/set),而访问器描述符和数据描述符互斥。比较前应先判断类型,再按规则比对:
- 若任一描述符为
undefined,说明属性不存在,直接视为不等 - 若一个含
get或set,另一个不含,则类型不同,不等 - 数据描述符比对
value(严格相等)、writable、enumerable、configurable - 访问器描述符比对
get和set(函数引用相等)、enumerable、configurable
处理函数引用与不可序列化值
描述符中的 value 或 get/set 是函数或任意值,=== 可用于函数引用比对(同一函数实例),但不能用深比较替代——因为描述符语义上要求“同一个 getter 函数”,而非“行为相同”。例如:
const obj1 = { get x() { return 1; } };
const obj2 = { get x() { return 1; } };
// 即使逻辑相同,obj1 和 obj2 的 getter 是不同函数,描述符不等
因此,不要用 Lodash 的 isEqual 或自定义深比较,避免误判。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
封装可复用的比较函数
可写一个轻量工具函数,聚焦于描述符语义一致性:
function equalDescriptor(descA, descB) {
if (!descA || !descB) return descA === descB;
const hasGet = 'get' in descA || 'set' in descA;
const hasGetB = 'get' in descB || 'set' in descB;
if (hasGet !== hasGetB) return false;
if (hasGet) {
return (
descA.enumerable === descB.enumerable &&
descA.configurable === descB.configurable &&
descA.get === descB.get &&
descA.set === descB.set
);
}
return (
descA.enumerable === descB.enumerable &&
descA.configurable === descB.configurable &&
descA.writable === descB.writable &&
descA.value === descB.value
);
}
调用时传入两个描述符对象即可,无需预处理。
批量比较多个属性时注意属性名一致性
若要比较两个对象所有属性的描述符,需先获取双方自有属性名交集(用 Object.getOwnPropertyNames 或 Reflect.ownKeys),再逐个比对。遗漏属性名会导致跳过缺失项,造成误判:
- 仅比交集属性:确保两边都存在该属性才比较描述符
- 若要求“完全一致”,还需检查各自是否有对方没有的属性(即长度与键名是否完全相同)
- 注意 Symbol 属性:
Reflect.ownKeys包含 Symbol,Object.keys不包含
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










