如何通过Array.reduce()的reducer函数复制对象原型并保留大写键
解决方案
核心问题分析
你当前的代码中,reduce的初始值是普通空对象{},它的原型是Object.prototype,因此无法继承原feature对象的原型链。而直接使用Object.setPrototypeOf(accumulator, item)会让新对象的原型指向原item本身,导致原item的自身属性(包括小写键)通过原型链被访问到,最终出现大小写属性并存的问题。
优化实现方式
我们可以直接创建继承原对象原型的空对象作为初始值,再手动添加处理后的属性,这样既能保留原型链,又不会引入原对象的自身属性。
写法一(基于原reduce逻辑修改)
function doCapitalizeFeatureKeys(in_obj){ if(in_obj.features && in_obj.features.length > 0){ const obj2 = in_obj.features.map(item => { // 获取原item的原型,创建继承该原型的空对象作为accumulator初始值 const itemProto = Object.getPrototypeOf(item); return Object.keys(item).reduce((accumulator, currentValue) => { if(currentValue === "attributes" && item[currentValue]){ // 可选:让attributes对象也继承原attributes的原型 const attrProto = Object.getPrototypeOf(item[currentValue]); const cap = Object.keys(item[currentValue]).reduce((acc, curr) => { acc[curr.toUpperCase()] = item[currentValue][curr]; return acc; }, Object.create(attrProto)); accumulator[currentValue] = cap; } else { accumulator[currentValue] = item[currentValue]; } return accumulator; }, Object.create(itemProto)); }); in_obj.features = obj2; return in_obj; } return in_obj; }
写法二(更简洁的版本)
使用Object.fromEntries替代嵌套reduce,代码可读性更强:
function doCapitalizeFeatureKeys(in_obj){ // 提前判断,简化逻辑 if(!in_obj.features?.length) return in_obj; in_obj.features = in_obj.features.map(item => { // 创建继承原item原型的新对象 const newFeature = Object.create(Object.getPrototypeOf(item)); // 遍历原item的所有自身属性 for(const key of Object.keys(item)){ if(key === "attributes" && item[key]){ // 将attributes的键转大写,同时可选继承原attributes的原型 const attrProto = Object.getPrototypeOf(item[key]); newFeature[key] = Object.assign( Object.create(attrProto), Object.fromEntries( Object.entries(item[key]).map(([k, v]) => [k.toUpperCase(), v]) ) ); } else { // 其他属性直接赋值 newFeature[key] = item[key]; } } return newFeature; }); return in_obj; }
关键说明
- 原型继承:通过
Object.create(Object.getPrototypeOf(item))创建的新对象,直接继承原item的原型链,不会包含原item的自身属性。 - 属性控制:我们只手动添加需要保留的属性(处理后的
attributes和其他原样属性),因此新对象不会出现原小写属性的残留。 - 可选扩展:如果不需要
attributes对象继承原型,可以去掉Object.create(attrProto)相关代码,直接使用Object.fromEntries的结果即可。
内容的提问来源于stack exchange,提问作者M Alok
相关产品推荐
相关产品推荐

