对于数组,我们可以使用.map
方法来创建具有相同数组结构(即,元素数量相同)的新地图。
例如
const array = [2, 4, 6];
const newArray = array.map(v => v *2); //[4, 8, 12];
我相信在函数式编程中,这会使数组对象称为functor。
对于对象,我想做类似的事情-我想创建一个具有与原始对象相同的结构(相同的键)以及相同的功能等的新对象。
例如
const obj = {
foo: 2,
bar: 4,
biz: 6
};
const newObj = obj.map(v => v *2); // {foo: 4, bar: 8, biz: 12}
我当前的操作方式是使用Object.entries
和.reduce
:
const obj = {
foo: 2,
bar: 4,
biz: 6
};
const newObj = Object.entries(obj).reduce((acc,cur) => {
return {
...acc,
[cur[0]]: cur[1] * 2
}
}, {});
console.log(newObj);
我想知道-当前是否存在一个对象方法,该方法可以让我执行我丢失的操作?还是提议增加一个?
答案 0 :(得分:3)
没有对象的本机映射,但是可以轻松地创建对象。我认为条目是最简单的。
const obj = { foo: 2, bar: 4, biz: 6 }
const objMap = (obj, fn) =>
Object.fromEntries(
Object.entries(obj).map(
([k, v], i) => [k, fn(v, k, i)]
)
)
console.log(
objMap(obj, v => v * 2),
objMap(obj, (v, k) => `${k}-${v}`),
objMap(obj, (v, _, i) => v * i)
)
答案 1 :(得分:3)
用于对象的map
函数很容易定义。
Object.defineProperty(Object.prototype, "map", {
value(mapping) {
const oldEntries = Object.entries(this);
const newEntries = oldEntries.map(([key, val]) => [key, mapping(val)]);
return Object.fromEntries(newEntries);
}
});
const obj = { foo: 2, bar: 4, baz: 6 };
const result = obj.map(x => 2 * x);
console.log(result);
请注意,这与kornieff的objMap
函数不同,因为映射函数无法访问或更改密钥。因此,这是Functor
类型的对象的正确实现。
作为奖励,让我们为对象实现一些其他有用的类型类。首先,是Representable
类型的类。
Object.tabulate = table => new Proxy({}, {
get: (_, key) => table(key)
});
const object = Object.tabulate(key => {
if (key === "foo") return 10;
if (key === "bar") return 20;
return 30;
});
console.log(object.foo); // 10
console.log(object.bar); // 20
console.log(object.baz); // 30
tabulate
函数可用于定义各种有用的类型类,例如Monad
和Comonad
。例如,让我们实现Distributive
类型类。我将其他类型类的实现留给读者练习。
Object.tabulate = table => new Proxy({}, {
get: (_, key) => table(key)
});
const distribute = functor => Object.tabulate(key =>
functor.map(object => object[key]));
const result1 = distribute([ { foo: 10, bar: 20 }, { foo: 30, bar: 40 } ]);
console.log(result1.foo); // [ 10, 30 ]
console.log(result1.bar); // [ 20, 40 ]
Object.defineProperty(Object.prototype, "map", {
value(mapping) {
const oldEntries = Object.entries(this);
const newEntries = oldEntries.map(([key, val]) => [key, mapping(val)]);
return Object.fromEntries(newEntries);
}
});
const result2 = distribute({ a: { foo: 10, bar: 20 }, b: { foo: 30, bar: 40 } });
console.log(result2.foo); // { a: 10, b: 30 }
console.log(result2.bar); // { a: 20, b: 40 }
请注意,distribute
需要一个具有map
方法的对象,这就是为什么我们在map
上定义了Object.prototype
方法的原因。但是,我们可以使用Yoneda
引理来解决此限制。
答案 2 :(得分:0)
一种方法:
const obj = {
foo: 2,
bar: 4,
biz: 6
};
const x = Object.keys(obj).map(o => {
return {[o]: obj[o] * 2}
})
console.log(JSON.stringify(x, null, 2))
答案 3 :(得分:0)
使用.reduce()
的另一种方法是这样的,利用解构来读取内容更容易(我认为)
const obj = {
foo: 2,
bar: 4,
biz: 6
};
const newObj = Object.entries(obj).reduce(
(acc, [key, value]) => ({...acc, [key]: value * 2}), {}
);
console.log(newObj)
答案 4 :(得分:0)
如果您想在代码中尝试一些功能性api, 那么您可以考虑使用功能库(例如Ramda),
它不仅介绍了对象(地图)的仿函数api,还介绍了其他很酷的东西!
const input = { a: 1, b: 44, c: 77 };
const doubled = R.map(R.multiply(2), input);
console.log(
`doubling input`,
doubled,
);
// and a lot more...
const odds = R.filter(R.modulo(R.__, 2), input);
console.log(
`filtering odds only of input`,
odds,
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
答案 5 :(得分:0)