如何检查JavaScript对象中是否存在可被赋值的属性
解决方案
你遇到的问题核心是in关键字仅能判断属性是否存在于对象或其原型链上,无法校验属性是否支持赋值,所以遇到仅定义了getter的访问器属性时就会触发报错。你可以通过以下两种方案解决:
方案1:通过属性描述符判断可写性
通过Object.getOwnPropertyDescriptor顺着原型链查找对应属性的描述符,判断属性是否支持赋值:
/** * 检查对象指定属性是否可被赋值 * @param {object} obj 目标对象 * @param {string} propName 要检查的属性名 * @returns {boolean} 属性是否可写 */ function isPropertyWritable(obj, propName) { // 已冻结的对象所有属性不可写 if (Object.isFrozen(obj)) return false; let currentProto = obj; // 顺着原型链查找属性描述符 while (currentProto) { const descriptor = Object.getOwnPropertyDescriptor(currentProto, propName); if (descriptor) { // 数据属性判断writable配置,访问器属性判断是否存在setter return 'writable' in descriptor ? descriptor.writable : !!descriptor.set; } currentProto = Object.getPrototypeOf(currentProto); } // 若属性不存在,默认返回false(和原`in`判断逻辑保持一致:仅存在的属性才赋值) // 如果需要支持属性不存在时新增赋值,可改为 return !Object.isSealed(obj); return false; }
使用时替换原有的in判断即可:
const obj = new MyClass(); const value = '你要赋的值'; if (isPropertyWritable(obj, 'property')) { obj.property = value; }
方案2:try-catch兜底赋值
如果你的场景中存在Proxy代理对象、第三方封装对象等无法通过属性描述符判断的情况,可以直接用try-catch包裹赋值逻辑,容错性更强:
const obj = new MyClass(); const value = '你要赋的值'; try { obj.property = value; } catch (e) { // 仅捕获赋值权限类错误,其他错误正常抛出 if (!(e instanceof TypeError && e.message.includes('Cannot set property'))) { throw e; } // 可选:添加日志记录赋值失败的情况 console.warn(`属性<property>不可赋值,已忽略`); }
两种方案可以根据你的实际场景选择:
- 常规业务场景下优先选方案1,性能更高且无副作用
- 处理不确定类型的第三方对象时选方案2,兼容性更强
内容的提问来源于stack exchange,提问作者Nicholas Chiang
相关产品推荐
相关产品推荐

