草庐IT

javascript - 在高阶函数中传递附加参数

coder 2024-05-17 原文

考虑这个例子:

const samples = ["foo", "bar"];

const excludeFoos = function(item) {
  return item !== "foo";
}

const foos = samples.filter(excludeFoos);


我怎样才能通过 附加 excludeFoos 中的参数?

例如:

const samples = ["foo", "bar"];

const exclude = function(item, str) {
  return item !== str;
}

// obviously won't work but you get the point
const foos = samples.filter(exclude("foo"));
console.log(foos); // ["bar"]

最佳答案

为事物命名

"If you have the name of a spirit, you have power over it." – Gerald Jay Sussman



你能为你的exclude 想一个更好的名字吗?功能?我知道我可以。它被称为 notEqual .在解决问题时,只需知道它的真实名称,它就会变得更加通用。 “排除”在过滤数组的上下文中是有意义的,但不知何故,如果我们想使用 exclude在别处发挥作用。
if (exclude(a,b))
  console.log("a and b are not equal")

函数式编程就是让函数尽可能地可重用,所以在我们前进的过程中,让我们坚持下去
const notEqual = (x,y) => x !== y

Function.prototype.bind

Function.prototype.bind用于将值绑定(bind)到函数参数。它之所以被广泛使用,是因为它自 ECMAScript 5 以来一直是原生的——这意味着您无需添加任何额外的依赖项或对现有代码进行任何更改即可实现您的目标。

const notEqual = (x,y) => x !== y

const samples = ['foo', 'bar']

const foos = samples.filter(notEqual.bind(null, 'foo'))

console.log(foos) // ["bar"]


部分申请

Partial application接受一个函数和一些参数并产生另一个较小的函数 – arity是“函数接受的参数数量”的花哨词

既然你已经熟悉了 Function.prototype.bind ,你已经知道部分应用了。唯一的区别是 bind强制您提供绑定(bind)的上下文。在大多数函数式程序中,上下文是一个麻烦,所以有时拥有一个让我们部分应用而不用关心上下文的函数会更容易。

const partial = (f, ...xs) => (...ys) => f(...xs, ...ys)

const notEqual = (x,y) => x !== y

const samples = ['foo', 'bar']

const foos = samples.filter(partial(notEqual, 'foo'))

console.log(foos) // ["bar"]


curry

Currying ,虽然类似于部分应用程序,但它是解决问题的另一种方法。柯里化(Currying)采用多个参数的函数并将其转换为一系列一元函数——每个函数都有一个参数。

const notEqual = (x,y) => x !== y

const curry = f => x => y => f(x,y)

const samples = ['foo', 'bar']

const foos = samples.filter(curry(notEqual)('foo'))

console.log(foos) // ["bar"]


如果您无法看到这与部分应用程序有何不同,请注意在函数数量大于 2 之前您不会看到太大差异 – 另请参阅:contrast currying with partial application .

如您所见,可读性开始受到一点影响。如果 notEqual在我们的控制之下,我们可以从一开始就以 curry 形式定义它

const notEqual = x => y => x !== y

const samples = ['foo', 'bar']

const foos = samples.filter(notEqual('foo'))

console.log(foos) // ["bar"]


你可能甚至没有注意到它,但是 partial (上)定义为 curry 风格!

Related: "What do multiple arrow functions mean in JavaScript?"



柯里化(Currying)是一个非常强大的概念,并以多种方式有用。你可能会说解决这个单一的、孤立的问题太过分了,你是对的。当柯里化(Currying)在程序或语言中被广泛使用时,你才会真正开始看到它的好处,因为它有一个 systemic effect。 ——最终,它提供了对函数本身的抽象。

const apply = f => x => f (x)

const notEqual = x => y => x !== y

const filter = f => xs => xs.filter(apply(f))

const notFoo = filter(notEqual('foo'))

const samples = ['foo', 'bar']

console.log(notFoo(samples)); // ["bar"]


最后评论

有很多选项可供您选择,您可能想知道哪个是“正确”的选择。如果你正在寻找 Elixir ,你会很难过得知没有 Elixir 。与所有事物一样,都有取舍。

我发现部分/过程应用程序是一个不可或缺的工具,因此我尝试以完全柯里化(Currying)的形式编写我的所有 JavaScript 函数。这样我就避免了对 partial 的调用和 curry遍及我的程序。这样做的结果是代码最终看起来有点陌生,起初 – comparison functorround-robinmake anything you wanthigher-order generators and DIY iteratorsid generatorgeneric function repetitionmerge/flatten arraycustom iteration

并非您程序的所有部分都完全在您的控制之下,对吧?当然,您可能正在使用一些外部依赖项,它们不太可能拥有您正在寻找的完美功能界面。在这种情况下,您最终会使用 partialcurry与您无法更改的其他代码交互。

最后,看看那里的一些函数库,如 folktalkeRamda .我不建议初学者使用函数式程序员,但是在你咬牙切齿之后值得研究的东西。

关于javascript - 在高阶函数中传递附加参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41947031/

有关javascript - 在高阶函数中传递附加参数的更多相关文章

  1. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  2. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  3. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  6. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  7. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

随机推荐