应通过 object.getownpropertydescriptor 检查属性描述符中是否存在 get 或 set 函数来判断是否被 object.defineproperty 劫持;若 desc 为 undefined 则属性不存在,若含 value 则为普通数据属性,仅修改 writable 不构成劫持。

直接检测被 Object.defineProperty 劫持的属性,不能靠常规的 in、hasOwnProperty 或 for...in 判断是否“存在”——因为这些方法只反映属性的枚举性(enumerable),而劫持本身不改变属性是否存在,只改变读写行为。关键在于:**你真正想检测的是“该属性是否被定义为访问器属性(accessor property)”,即是否有自定义的 get 或 set**。
检查属性是否为访问器属性
使用 Object.getOwnPropertyDescriptor 获取属性描述符,再判断是否存在 get 或 set 函数:
const desc = Object.getOwnPropertyDescriptor(obj, 'prop');- 如果
desc && (typeof desc.get === 'function' || typeof desc.set === 'function'),说明该属性被defineProperty劫持过(至少挂了 get 或 set) - 注意:返回
undefined表示该属性根本不存在;返回对象但value和writable存在,则是普通数据属性,未被劫持
区分劫持属性和普通属性的典型表现
被劫持的属性常有以下可观察特征,可用于辅助判断:
- 读取或赋值时触发额外逻辑(如控制台打印、请求发送、视图更新),但代码里没显式调用
- 属性不可枚举(
enumerable: false),导致for...in或Object.keys()找不到它 - 属性不可配置(
configurable: false),执行delete obj.prop返回false,且再次defineProperty会报错 - 尝试用
Object.defineProperty重定义同一属性失败,提示 “Cannot redefine property”
避免误判的常见陷阱
有些现象看似像劫持,实则与 defineProperty 无关:
-
obj.toString等原型链上的方法,其描述符含get是正常行为,不是人为劫持 - Proxy 对象的拦截行为无法通过
getOwnPropertyDescriptor检测,它返回的是目标对象的原始描述符,不是代理层逻辑 - Vue 2 响应式对象中,
_ob_这类内部属性是访问器,但属于框架私有实现,不应作为业务逻辑检测依据 - 只改了
value和writable(比如设为false),没写get/set,不算“劫持”,只是冻结了写权限
实际调试建议
开发中快速验证某属性是否被劫持:
- 在浏览器控制台输入
Object.getOwnPropertyDescriptor(obj, 'xxx'),展开结果看字段 - 临时加一句
obj.xxx = obj.xxx,观察是否触发 setter 日志或副作用 - 用
console.dir(obj)查看对象,在属性旁若有「getter」或「setter」小图标,就是访问器属性 - 对 Vue 实例,可用
obj.$data配合__ob__判断是否已响应式化(但这是 Vue 内部机制,非通用方案)











