我有一个目标:
myObject = { 'a': 1, 'b': 2, 'c': 3 }
我正在寻找一个本地方法,类似于Array.prototype.map,可按如下方式使用:
newObject = myObject.map(function (value, label) {
return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }
JavaScript是否有这样的对象映射函数?(我希望Node.JS使用这个,所以我不关心跨浏览器问题。)
const mapObject = (targetObject, callbackFn) => {
if (!targetObject) return targetObject;
if (Array.isArray(targetObject)){
return targetObject.map((v)=>mapObject(v, callbackFn))
}
return Object.entries(targetObject).reduce((acc,[key, value]) => {
const res = callbackFn(key, value);
if (!Array.isArray(res) && typeof res ==='object'){
return {...acc, [key]: mapObject(res, callbackFn)}
}
if (Array.isArray(res)){
return {...acc, [key]: res.map((v)=>mapObject(v, callbackFn))}
}
return {...acc, [key]: res};
},{})
};
const mapped = mapObject(a,(key,value)=> {
if (!Array.isArray(value) && key === 'a') return ;
if (!Array.isArray(value) && key === 'e') return [];
if (!Array.isArray(value) && key === 'g') return value * value;
return value;
});
console.log(JSON.stringify(mapped));
// {"b":2,"c":[{"d":2,"e":[],"f":[{"g":4}]}]}
此函数递归地遍历对象和对象数组。如果返回未定义,则可以删除属性
您可以在返回的键数组上使用Object.keys和forEach:
var myObject = { 'a': 1, 'b': 2, 'c': 3 },
newObject = {};
Object.keys(myObject).forEach(function (key) {
var value = myObject[key];
newObject[key] = value * value;
});
或者以更模块化的方式:
function map(obj, callback) {
var result = {};
Object.keys(obj).forEach(function (key) {
result[key] = callback.call(obj, obj[key], key, obj);
});
return result;
}
newObject = map(myObject, function(x) { return x * x; });
请注意,Object.keys返回的数组只包含对象自己的可枚举财产,因此其行为类似于for。。在循环中使用hasOwnProperty检查。
公认的答案有两个缺点:
它误用了Array.prototype.reduce,因为reduce意味着改变复合类型的结构,这在这种情况下不会发生。它不是特别可重复使用
ES6/ES2015功能方法
请注意,所有函数都是以货币形式定义的。
//小型、可重复使用的辅助功能constkeys=o=>对象.keys(o);constassign=(…o)=>对象.assign({},…o);const-map=f=>xs=>xs.map(x=>f(x));常量mul=y=>x=>x*y;常量sqr=x=>mul(x)(x);//实际地图功能常量omap=f=>o=>{o=分配(o);//A.映射(x=>o[x]=f(o[x]))(键(o));//B返回o;};//模拟数据常量o={“a”:1,“b”:2,“c”:3};//并运行控制台日志(omap(sqr)(o));控制台日志(omap(mul(10))(o));
在线A o被重新分配。由于Javascript通过共享传递引用值,因此生成了o的浅拷贝。我们现在能够在omap中突变o,而不在父作用域中突变o。在B行中,map的返回值被忽略,因为map执行了o的变异。由于此副作用仍在omap中,并且在父范围中不可见,因此完全可以接受。
这不是最快的解决方案,而是一个声明性和可重用的解决方案。以下是与单行相同的实现,简洁但可读性较差:
const omap = f => o => (o = assign(o), map(x => o[x] = f(o[x])) (keys(o)), o);
附录-为什么默认情况下对象不可迭代?
ES2015指定了迭代器和可迭代协议。但对象仍然不可迭代,因此不可映射。原因是数据和程序级别的混合。
为了更准确地响应OP的要求,OP需要一个对象:
myObject={“a”:1,“b”:2,“c”:3}
要使用映射方法myObject.map,
类似于Array.prototype.map,使用如下:newObject=myObject.map(函数(值,标签){返回值*值;});//newObject现在是{“a”:1,“b”:4,“c”:9}
imho最佳答案(以“接近要求的内容”+“不需要ES{5,6,7}”来衡量)是:
myObject.map = function mapForObject(callback)
{
var result = {};
for(var property in this){
if(this.hasOwnProperty(property) && property != "map"){
result[property] = callback(this[property],property,this);
}
}
return result;
}
上面的代码避免故意使用任何语言特性,这些特性仅在最近的ECMAScript版本中可用。使用上面的代码,问题可以通过以下方式解决:
myObject={“a”:1,“b”:2,“c”:3};myObject.map=函数mapForObject(回调){var结果={};for(此中的var属性){如果(this.hasOwnProperty(property)&&property!=“地图”){result[property]=回调(this[property],property,this);}}返回结果;}newObject=myObject.map(函数(值,标签){返回值*值;});console.log(“newObject is now”,newObject);此处为备选测试代码
除了受到一些人的反对外,还可以像这样将解决方案插入到原型链中。
Object.prototype.map = function(callback)
{
var result = {};
for(var property in this){
if(this.hasOwnProperty(property)){
result[property] = callback(this[property],property,this);
}
}
return result;
}
在仔细监督的情况下进行的操作不会产生任何不良影响,也不会影响其他对象的贴图方法(即阵列的贴图)。