如何让JavaScript对象(如ServiceWorkerRegistration)的属性可枚举?
如何让ServiceWorkerRegistration对象的属性变为可枚举?
问题描述
我通过以下代码获取了一个ServiceWorkerRegistration类型的对象:
const reg = await navigator.serviceWorker.register(`https://www.myurl.com/Worker.js`, {scope:"/"});
使用console.log(reg)能看到对象的各类属性,但执行JSON.stringify(reg)返回{},Object.keys(reg)返回[],经查这是因为对象的属性不可枚举。目前只能手动访问单个属性或逐个设置属性为可枚举,我希望能通过Object.keys(reg).forEach遍历属性,请问如何让该对象的属性变为可枚举?
解决方案
方案1:修改原对象属性为可枚举(遍历原型链)
ServiceWorkerRegistration的多数属性定义在原型链上且不可枚举,我们可以递归遍历其原型链,将所有属性的可枚举性设为true:
function makeAllPropertiesEnumerable(obj) { let currentObj = obj; while (currentObj !== null) { const props = Object.getOwnPropertyNames(currentObj); props.forEach(prop => { const descriptor = Object.getOwnPropertyDescriptor(currentObj, prop); if (descriptor && !descriptor.enumerable) { descriptor.enumerable = true; Object.defineProperty(currentObj, prop, descriptor); } }); currentObj = Object.getPrototypeOf(currentObj); } } // 使用示例 makeAllPropertiesEnumerable(reg); // 现在可以正常遍历 Object.keys(reg).forEach(key => { console.log(`属性名:${key},值:${reg[key]}`); });
方案2:创建包含所有属性的普通对象(无副作用)
如果不想修改原对象的属性描述符,更安全的方式是创建一个普通对象,把原对象(包括原型链上)的所有属性拷贝进去:
function getEnumerableClone(obj) { const clone = {}; let currentObj = obj; while (currentObj !== null) { Object.getOwnPropertyNames(currentObj).forEach(prop => { clone[prop] = currentObj[prop]; }); currentObj = Object.getPrototypeOf(currentObj); } return clone; } // 使用示例 const enumerableReg = getEnumerableClone(reg); Object.keys(enumerableReg).forEach(key => { console.log(`属性名:${key},值:${enumerableReg[key]}`); });
注意事项
- 浏览器宿主对象(如
ServiceWorkerRegistration)的属性不可枚举是浏览器的设计规范,修改其属性描述符可能存在未知风险,建议在测试环境充分验证后再投入生产。 - 方案2无需修改原对象,避免了潜在副作用,更适合大多数场景。
内容的提问来源于stack exchange,提问作者Null Salad
相关产品推荐
相关产品推荐

