Considering this code, using Ramda 0.21.0:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
)
console.log(foo({ a: 1, b: 2})) // { a: 2, b: 3 }
console.log(foo({ c: 3, d: 4})) // { a: 2, b: 3, c: 4, d: 5 }
Why does the second call to foo
display { a: 2, b: 3, c: 4, d: 5 }
instead of { c: 4, d: 5 }
?
Is there some kind of memoization going on? I would expect the initial value of acc
to be reset to {}
each time foo is applied.
答案 0 :(得分:4)
这个答案大多扩展了@iofjuupasli
的评论问题是累加器对象的变异。你在foo
的定义中创建一个,在每个调用中重复使用,然后你在iteratee
更新它(可怕的名字,恕我直言。称之为bar
或其他东西。:-)) 。有几种方法可以解决这个问题。一种可能是确保在每次调用foo
时传递新的累加器:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
list => R.reduce(iteratee, {}, list)
)
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
这有效,但感觉不满意。也许更有帮助的是避免在每次传递时改变累加器对象。 assoc
将创建一个新对象,尽可能多地重用前一个对象:
var iteratee = (acc, [k, v]) => R.assoc(k, v + 1, acc)
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
这看起来更干净。但实际上Ramda有一个更简单的解决方案。 map
函数将对象视为要映射的函子。将其与inc
相结合,只需增加一个值,我们就可以这样做:
var foo = R.map(R.inc);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
感觉非常干净!