我们什么时候可以将展开函数作为参数传递

问题描述

在Javascript和许多其他编程语言中,我们可能会将函数作为参数传递给其他函数。这是函数式编程中的一种常见做法。

我们知道包装器需要在其中放置一个断点,以查看其在堆栈跟踪中的位置,以更好地控制参数或在调用之前/之后添加逻辑。

还有其他客观原因不将展开函数作为参数传递吗?

myFunction1(x => myFunction2(x)) // wrapped
myFunction1(myFunction2) // unwrapped

解决方法

“应该”使用一种或另一种技术在SO中大部分是禁止的。

不过,我将回答一个相关的问题,关于何时可以使用该技术以及不能使用该技术以及可能存在的(不利)优势。

您始终可以写std::fstream dwrite; dwrite >> /* ... */; // ok dwrite << /* ... */; // ok 。您不能总是写foo (x => bar (x))。在another Q & A中可以找到为什么的示例。根据我的经验,一个常见的例子是带有第二个参数的递归函数,该参数在初始调用中默认,并在后续调用中传递。通过简单引用foo (bar)不能成功传递此函数,因为map除了期望值之外还提供其他参数。

但这是不寻常的情况。如果您的函数没有默认参数,则在包装器中似乎没什么用。一个论点就是,如果要用map代替foo (bar),为什么不更进一步,而使用foo (x => bar (x))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周围的Promise包装器也是如此。它不会损害结果,只会对性能产生很小的影响,但几乎无法平衡混乱情况。

(而且,我试图在这里避免发表意见,但实际上是不可能的。)

,

您无需使用匿名函数包装函数即可将其分配为事件处理程序。如果函数应该获取事件对象,就可以了。

window.addEventListener('click',myFunction)

此外,用匿名函数包装该函数将阻止您删除事件处理程序,因为remove期望与添加的事件处理程序相同。

这将起作用:

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)

只有一层不必要的间接调用;)

这与函数式编程或currying无关,我看不到它如何阻碍您的调试经验。

当您想锁定某些参数或签名不兼容时,通常会包装。例如,

call(a => foo(5,a))

但是在这种情况下,您可能需要考虑使用curring。