问题描述
以下代码以功能方式编写。有一个要购买的用户对象。过程如下:将商品添加到购物车,添加税款,购买该商品并将其推送到用户的购买历史记录数组中。然后,最后将原来的购物车清空。这全部通过使用reduce函数来完成,该函数具有一个compose函数。
我要努力理解的是在这种情况下reduce函数是如何工作的。根据我的理解,compose函数是作为reduce的回调函数传递的。组成函数中的f表示累加器,g表示数组中的项。
const user = {
name: 'Kim',active: true,cart: [],purchases: []
}
const compose = (f,g) => (...args) => {
console.log(1,f);
console.log(2,g);
return f(g(...args));
}
// The below code is commented out so that I can visualize it in a more simple manner
//purchaseItem (
// emptyCart,// buyItems,//applyTaxToItems,// addItemToCart
//)(user,{name: 'laptop',price: 244});
function purchaseItem(...fns) {
console.log(fns);
return fns.reduce(compose);
}
// Here is each piece broken down to be passed into reduce and the arguments the compose function takes
console.log([emptyCart,buyItems,applyTaxToItems,addItemToCart].reduce(compose)(user,price: 244}));
function addItemToCart(user,item) {
const updateCart = user.cart.concat(item);
return Object.assign({},user,{ cart: updateCart });
}
function applyTaxToItems(user,item) {
return user
}
function buyItems(user,item) {
return user
}
function emptyCart(user,item) {
return user
}
输出如下:
1 [Function]
2 [Function: addItemToCart]
1 [Function]
2 [Function: applyTaxToItems]
1 [Function: emptyCart]
2 [Function: buyItems]
{ name: 'Kim',cart: [ { name: 'laptop',price: 244 } ],purchases: [] }
我试图映射f和g元素的流。我知道f可以容纳compose函数返回的任何值,但是为什么初始值是匿名函数。此外,为什么item元素从数组中的最后一个元素开始并向后工作?我也对为什么emptyCart函数在reduce的最后一个循环中变为f值感到困惑。如果有人可以向我解释这一点,我将非常感激。谢谢。
解决方法
您的日志未正确映射执行流程。
您首先登录f
,然后登录g
,但是对于f(g(x))
,g
首先被评估,然后是f
。 f(g(x)
可以读作“ x of g之后的f”或“ x of g of f”。
以同样的方式,当您使用诸如f(g(...x))
之类的化简器对一组函数进行归约时,它们将以相反的顺序求值,因为结果函数的行为类似于f(g(h(x)))
。
有关更多说明,请参见下面的代码。 compose2
与您的compose
函数相同,但日志记录更为繁重。
如果运行下面的代码,可能会更好地了解发生了什么。为了评估由归约/合成产生的函数,我们评估了f(g(...args))
形式的多个函数。
请注意,g(...args)
的结果如何在最终结果向下传播之前全部向上传播。
const compose2 = (f,g,i) => {
const name = `${f.name} after ${g.name}`;
const h = {[name]: (...args) => {
console.log(i,'f:',f.name);
console.log(i,'g:',g.name);
console.log(i,'args to g:',...args);
console.log(i,'g(...args):',g(...args));
console.log(' ');
const res = f(g(...args));
console.log(i,'result:',res);
return res;
}}[name];
return h;
}
const f_xe = x => x + 'e',f_xd = x => x + 'd',f_xc = x => x + 'c',f_xy = (x,y) => x + y;
console.log([f_xe,f_xd,f_xc,f_xy].reduce(compose2)('a','b'));