我们什么时候可以将未包装的函数作为参数传递
When can we pass an unwrapped function as a parameter
在Javascript和许多其他编程语言中,我们可以将函数作为参数传递给其他函数。这是函数式编程中的常见做法。
我们知道包装器需要在此处放置断点、查看它在堆栈跟踪中的位置、更好地控制参数或添加逻辑 before/after 调用。
是否有其他 objective 理由不将展开的函数作为参数传递?
myFunction1(x => myFunction2(x)) // wrapped
myFunction1(myFunction2) // unwrapped
您无需使用匿名函数包装函数即可将其指定为事件处理程序。如果函数应该获取事件对象,这很好。
window.addEventListener('click', myFunction)
此外,用匿名函数包装函数会阻止您删除事件处理程序,因为删除需要与添加的事件处理程序相同的事件处理程序。
这会起作用:
window. removeEventListener('click', myFunction)
这不会:
window.removeEventListener('click', e => myFunction(e))
如果您需要将更多参数传递给事件处理程序,您需要对其进行柯里化,并将返回的函数分配给一个变量,这样您就可以删除处理程序:
const createEventHandler = param => e => {}
const eventHandler = createEventHandler(true)
window.addEventListener('click', eventHandler)
// ...
window.removeEventListener('click', eventHandler)
call(e => foo(e))
完全相同:
call(foo)
只有一层不必要的间接访问 ;)
这与函数式编程或柯里化无关,我看不出它会如何影响您的调试体验。
当您想锁定某些参数或签名不兼容时,您通常会换行。例如,
call(a => foo(5, a))
但在这种情况下,您可能需要考虑柯里化。
询问“应该”使用一种或另一种技术主要是 off-limits 在 SO 中。
不过,我将回答一个相关问题,即何时可以和不可以使用该技术以及可能存在哪些(不利)优势。
你总是可以写foo (x => bar (x))
。你不能总是写 foo (bar)
。在 another Q & A 中可以找到原因的示例。根据我的经验,一个常见的例子是带有第二个参数的递归函数,该参数在初始调用中默认并传递给后续调用。这样的函数无法通过简单引用 map
成功传递,因为 map
提供了除预期值之外的其他参数。
但这是不寻常的情况。如果您的函数没有默认参数,则包装器似乎没什么用处。一个论点很简单,如果您要用 foo (x => bar (x))
替换 foo (bar)
,为什么不更进一步并使用 foo (y => (x => bar (x)) (y))
或 foo (z => (y => (x => bar (x)) (y)) (z))
.
包装器可以工作,但什么也没有添加...除了,正如您指出的那样,作为挂起断点的地方。
这对您来说可能是合法的案例。这些天我在调试器上花的时间不多,但是当我这样做的时候,我可能偶尔会临时添加这样一个包装器。但我之后删除它们。我发现干净的代码非常重要,不必要的包装器只会让事情变得混乱。在代码审查中,我 运行 经常反对这种模式:
const foo = (...args) => {
// do something with args
return new Promise ((resolve, reject) => {
bar (something).then(
(a) => {
resolve (a);
}, (err) => {
reject (err);
}
);
});
}
我一直需要指出的可以更清楚地写成:
const foo = (...args) => {
// do something with args
return new Promise ((resolve, reject) => {
bar (something) .then (resolve, reject);
});
}
那我还要进一步指出,即使这样也可以更好地写成
const foo = (...args) => {
// do something with args
return bar (something);
}
关键是 resolve
和 reject
周围的函数包装器只是混乱。 bar
周围的 Promise 包装器也是如此。它不会影响结果,对性能的影响很小,但它几乎无法平衡混乱。
(看,我试图在这里回避意见,但真的不能。)
在Javascript和许多其他编程语言中,我们可以将函数作为参数传递给其他函数。这是函数式编程中的常见做法。
我们知道包装器需要在此处放置断点、查看它在堆栈跟踪中的位置、更好地控制参数或添加逻辑 before/after 调用。
是否有其他 objective 理由不将展开的函数作为参数传递?
myFunction1(x => myFunction2(x)) // wrapped
myFunction1(myFunction2) // unwrapped
您无需使用匿名函数包装函数即可将其指定为事件处理程序。如果函数应该获取事件对象,这很好。
window.addEventListener('click', myFunction)
此外,用匿名函数包装函数会阻止您删除事件处理程序,因为删除需要与添加的事件处理程序相同的事件处理程序。
这会起作用:
window. removeEventListener('click', myFunction)
这不会:
window.removeEventListener('click', e => myFunction(e))
如果您需要将更多参数传递给事件处理程序,您需要对其进行柯里化,并将返回的函数分配给一个变量,这样您就可以删除处理程序:
const createEventHandler = param => e => {}
const eventHandler = createEventHandler(true)
window.addEventListener('click', eventHandler)
// ...
window.removeEventListener('click', eventHandler)
call(e => foo(e))
完全相同:
call(foo)
只有一层不必要的间接访问 ;)
这与函数式编程或柯里化无关,我看不出它会如何影响您的调试体验。
当您想锁定某些参数或签名不兼容时,您通常会换行。例如,
call(a => foo(5, a))
但在这种情况下,您可能需要考虑柯里化。
询问“应该”使用一种或另一种技术主要是 off-limits 在 SO 中。
不过,我将回答一个相关问题,即何时可以和不可以使用该技术以及可能存在哪些(不利)优势。
你总是可以写foo (x => bar (x))
。你不能总是写 foo (bar)
。在 another Q & A 中可以找到原因的示例。根据我的经验,一个常见的例子是带有第二个参数的递归函数,该参数在初始调用中默认并传递给后续调用。这样的函数无法通过简单引用 map
成功传递,因为 map
提供了除预期值之外的其他参数。
但这是不寻常的情况。如果您的函数没有默认参数,则包装器似乎没什么用处。一个论点很简单,如果您要用 foo (x => bar (x))
替换 foo (bar)
,为什么不更进一步并使用 foo (y => (x => bar (x)) (y))
或 foo (z => (y => (x => bar (x)) (y)) (z))
.
包装器可以工作,但什么也没有添加...除了,正如您指出的那样,作为挂起断点的地方。
这对您来说可能是合法的案例。这些天我在调试器上花的时间不多,但是当我这样做的时候,我可能偶尔会临时添加这样一个包装器。但我之后删除它们。我发现干净的代码非常重要,不必要的包装器只会让事情变得混乱。在代码审查中,我 运行 经常反对这种模式:
const foo = (...args) => {
// do something with args
return new Promise ((resolve, reject) => {
bar (something).then(
(a) => {
resolve (a);
}, (err) => {
reject (err);
}
);
});
}
我一直需要指出的可以更清楚地写成:
const foo = (...args) => {
// do something with args
return new Promise ((resolve, reject) => {
bar (something) .then (resolve, reject);
});
}
那我还要进一步指出,即使这样也可以更好地写成
const foo = (...args) => {
// do something with args
return bar (something);
}
关键是 resolve
和 reject
周围的函数包装器只是混乱。 bar
周围的 Promise 包装器也是如此。它不会影响结果,对性能的影响很小,但它几乎无法平衡混乱。
(看,我试图在这里回避意见,但真的不能。)