"Undefined" 尝试在 Javascript 中重现功能管道时
"Undefined" when trying to reproduce a functional pipe in Javascript
我今天刚开始学习函数式编程,我正在尝试使用管道创建一个示例:
const pipe = (...fns) => x => fns.reduce((acc, f) => f(acc), x)
const buffs = [{ power: 5, type: 'SPEED' }, { power: 2, type: 'SPEED' }]
let pos = { x: 0, y: 0 }
const addToPos = pos => amount => ({ ...pos, x: pos.x + amount })
const add1ToPos = pos => addToPos(pos)(1)
const add2ToPos = pos => addToPos(pos)(2)
const addAll = pos => pipe(
add1ToPos,
add2ToPos,
)(pos)
pos = addAll(pos)
console.log(pos) // returns { x: 3, y: 0 } as expected
但是,当我尝试从 buffs
添加所有这些 power
到我的管道时,如下所示:
const addAll = pos => pipe(
add1ToPos,
add2ToPos,
addToPos(buffs.reduce((a, b) => a + b.power, 0))
)(pos)
我明白了
{ x: undefined[object Object] }
我真的不知道为什么会这样,因为它工作得很好:
const numbers = [{ num: 4, color: 'blue' }, { num: 5, color: 'red' }]
let total = 0
const addToTotal = total => amount => total + amount
const add1ToTotal = total => addToTotal(total)(1)
const addAll = total => pipe(
add1ToTotal,
addToTotal(numbers.reduce((a, b) => a + b.num, 0))
)(total)
total = addAll(total) // returns 10 as expected
我做错了什么?
我也是新手,但我想知道,为什么不将 const addToPos = pos => amount => ({ ...pos, x: pos.x + amount })
重写为 const addToPos = amount => pos => ({ ...pos, x: pos.x + amount })
const pipe = (...fns) => x => fns.reduce((acc, f) => f(acc), x)
const buffs = [{ power: 5, type: 'SPEED' }, { power: 2, type: 'SPEED' }]
let pos = { x: 0, y: 0 }
const addToPos = amount => pos => ({ ...pos, x: pos.x + amount })
const add1ToPos = addToPos(1)
const add2ToPos = addToPos(2)
const addAll = pos => pipe(
add1ToPos,
add2ToPos,
addToPos(buffs.reduce((a, b) => a + b.power, 0)),
)(pos)
pos = addAll(pos)
console.log(pos)
尝试更详细地解释为什么最后一个示例的 addAll 有效而第一个示例无效(抱歉,有点冗长):
所以首先,最后一个示例的 addAll 有点错误。让我们看看 addToTotal:
const addToTotal = total => amount => total + amount
如果你调用 addToTotal(4) 你得到的是一个看起来像 amount => 4 + amount
的新函数,请注意这里我们分配了 4 给总参数而不是数量参数,当我们可能希望留下 total => total + 4
,因为管道操作正试图将值添加到总数中。那么它为什么有效呢?加法运算的顺序无关紧要,amount => 4 + amount
和 total => total + 4
将始终产生相同的结果。
那么为什么第一个示例不起作用?
在第一个示例中,addAll 将一个 pos 对象传递给管道中的每个函数。最后一个函数是addToPos(buffs.reduce((a, b) => a + b.power, 0))
,什么是addToPos(buffs.reduce((a, b) => a + b.power, 0))
?好吧,如果我们想象 buffs.reduce((a, b) => a + b.power, 0)
是 5,它应该等同于:
addToPos(5)
这将是:
amount => ({ ...5, x: 5.x + amount })
当我们真正想要的是一个以 pos 作为参数的函数时;类似于:
pos => ({ ...pos, x: pos.x + 5 })
如果我们在调用链中交换 pos 和 amount(不确定这是不是正确的术语),我们得到:
addToPos = amount => pos => ({ ...pos, x: pos.x + amount })
如果我们对其应用金额,我们将得到一个将 pos 对象作为参数的函数。
如果函数是手写的,可能会更容易看到这些东西;原始 addToPos:
function addToPos(pos) {
return function(amount) {
return { ...pos, x: pos.x + amount };
}
}
addToPos 即returns一个以pos为参数的函数:
function addToPos(amount) {
return function(pos) {
return { ...pos, x: pos.x + amount };
}
}
我今天刚开始学习函数式编程,我正在尝试使用管道创建一个示例:
const pipe = (...fns) => x => fns.reduce((acc, f) => f(acc), x)
const buffs = [{ power: 5, type: 'SPEED' }, { power: 2, type: 'SPEED' }]
let pos = { x: 0, y: 0 }
const addToPos = pos => amount => ({ ...pos, x: pos.x + amount })
const add1ToPos = pos => addToPos(pos)(1)
const add2ToPos = pos => addToPos(pos)(2)
const addAll = pos => pipe(
add1ToPos,
add2ToPos,
)(pos)
pos = addAll(pos)
console.log(pos) // returns { x: 3, y: 0 } as expected
但是,当我尝试从 buffs
添加所有这些 power
到我的管道时,如下所示:
const addAll = pos => pipe(
add1ToPos,
add2ToPos,
addToPos(buffs.reduce((a, b) => a + b.power, 0))
)(pos)
我明白了
{ x: undefined[object Object] }
我真的不知道为什么会这样,因为它工作得很好:
const numbers = [{ num: 4, color: 'blue' }, { num: 5, color: 'red' }]
let total = 0
const addToTotal = total => amount => total + amount
const add1ToTotal = total => addToTotal(total)(1)
const addAll = total => pipe(
add1ToTotal,
addToTotal(numbers.reduce((a, b) => a + b.num, 0))
)(total)
total = addAll(total) // returns 10 as expected
我做错了什么?
我也是新手,但我想知道,为什么不将 const addToPos = pos => amount => ({ ...pos, x: pos.x + amount })
重写为 const addToPos = amount => pos => ({ ...pos, x: pos.x + amount })
const pipe = (...fns) => x => fns.reduce((acc, f) => f(acc), x)
const buffs = [{ power: 5, type: 'SPEED' }, { power: 2, type: 'SPEED' }]
let pos = { x: 0, y: 0 }
const addToPos = amount => pos => ({ ...pos, x: pos.x + amount })
const add1ToPos = addToPos(1)
const add2ToPos = addToPos(2)
const addAll = pos => pipe(
add1ToPos,
add2ToPos,
addToPos(buffs.reduce((a, b) => a + b.power, 0)),
)(pos)
pos = addAll(pos)
console.log(pos)
尝试更详细地解释为什么最后一个示例的 addAll 有效而第一个示例无效(抱歉,有点冗长):
所以首先,最后一个示例的 addAll 有点错误。让我们看看 addToTotal:
const addToTotal = total => amount => total + amount
如果你调用 addToTotal(4) 你得到的是一个看起来像 amount => 4 + amount
的新函数,请注意这里我们分配了 4 给总参数而不是数量参数,当我们可能希望留下 total => total + 4
,因为管道操作正试图将值添加到总数中。那么它为什么有效呢?加法运算的顺序无关紧要,amount => 4 + amount
和 total => total + 4
将始终产生相同的结果。
那么为什么第一个示例不起作用?
在第一个示例中,addAll 将一个 pos 对象传递给管道中的每个函数。最后一个函数是addToPos(buffs.reduce((a, b) => a + b.power, 0))
,什么是addToPos(buffs.reduce((a, b) => a + b.power, 0))
?好吧,如果我们想象 buffs.reduce((a, b) => a + b.power, 0)
是 5,它应该等同于:
addToPos(5)
这将是:
amount => ({ ...5, x: 5.x + amount })
当我们真正想要的是一个以 pos 作为参数的函数时;类似于:
pos => ({ ...pos, x: pos.x + 5 })
如果我们在调用链中交换 pos 和 amount(不确定这是不是正确的术语),我们得到:
addToPos = amount => pos => ({ ...pos, x: pos.x + amount })
如果我们对其应用金额,我们将得到一个将 pos 对象作为参数的函数。
如果函数是手写的,可能会更容易看到这些东西;原始 addToPos:
function addToPos(pos) {
return function(amount) {
return { ...pos, x: pos.x + amount };
}
}
addToPos 即returns一个以pos为参数的函数:
function addToPos(amount) {
return function(pos) {
return { ...pos, x: pos.x + amount };
}
}