我有一个目标:
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使用这个,所以我不关心跨浏览器问题。)
公认的答案有两个缺点:
它误用了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指定了迭代器和可迭代协议。但对象仍然不可迭代,因此不可映射。原因是数据和程序级别的混合。
没有到Object对象的本机映射,但这如何:
var myObject={“a”:1,“b”:2,“c”:3};Object.keys(myObject).forEach(函数(键,索引){myObject[key]*=2;});console.log(myObject);//=>{“a”:2,“b”:4,“c”:6}
但是您可以使用for。。。在:
var myObject={“a”:1,“b”:2,“c”:3};for(myObject中的var键){if(myObject.hasOwnProperty(键)){myObject[key]*=2;}}console.log(myObject);//{“a”:2,“b”:4,“c”:6}
使现代化
很多人都提到,以前的方法不会返回新对象,而是对对象本身进行操作。为此,我想添加另一个解决方案,该方案返回一个新对象并保持原始对象的原样:
var myObject={“a”:1,“b”:2,“c”:3};//返回一个新对象,其中每个键的值都使用mapFn(value)映射函数objectMap(对象,mapFn){return Object.keys(Object).reduce(function(result,key){result[key]=mapFn(对象[key])返回结果}, {})}var newObject=对象映射(myObject,函数(值){返回值*2})console.log(newObject);//=>{“a”:2,“b”:4,“c”:6}console.log(myObject);//=>{“a”:1,“b”:2,“c”:3}
Array.prototype.reduce通过将前一个值与当前值进行某种程度的合并,将数组缩减为单个值。链由空对象{}初始化。每次迭代时,都会添加myObject的一个新键,该键的值是该键的两倍。
使现代化
有了新的ES6特性,有了一种更优雅的方式来表达objectMap。
常量对象映射=(obj,fn)=>对象.fromEntries(对象条目(obj).map(([k,v],i)=>[k,fn(v,k,i)]))常量myObject={a:1,b:2,c:3}console.log(objectMap(myObject,v=>2*v))
我在谷歌搜索中发现了这一点,这是我试图学习如何做到这一点的第一个项目,我想我会与其他folsk分享我最近发现的解决方案,它使用了npm包不可变。
我觉得分享很有趣,因为不可变在他们自己的文档中使用了OP的EXACT情况——以下不是我自己的代码,而是从当前不可变的js文档中提取的:
const { Seq } = require('immutable')
const myObject = { a: 1, b: 2, c: 3 }
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 }
这并不是说Seq有其他财产(“Seq描述了一个惰性操作,允许它们通过不创建中间集合来高效地链接所有高阶集合方法(如map和filter)的使用”),也不是说其他一些不可变js数据结构也可以非常有效地完成这项工作。
任何使用此方法的人都必须npm安装不可变,并且可能需要阅读文档:
https://facebook.github.io/immutable-js/
写一个很简单:
Object.map = function(o, f, ctx) {
ctx = ctx || this;
var result = {};
Object.keys(o).forEach(function(k) {
result[k] = f.call(ctx, o[k], k, o);
});
return result;
}
示例代码:
> o = { a: 1, b: 2, c: 3 };
> r = Object.map(o, function(v, k, o) {
return v * v;
});
> r
{ a : 1, b: 4, c: 9 }
注意:这个版本还允许您(可选)为回调设置this上下文,就像Array方法一样。
EDIT-更改为删除Object.prototype的使用,以确保它不会与对象上任何现有的名为map的属性冲突。