Vac*_*cek 1 javascript higher-order-functions redux
我在一篇教程中看到了这段代码片段:
\nconst myFunction = () => {\n return function (caller) {\n caller(firstFuctnion());\n caller(secondFunction());\n };\n};\nRun Code Online (Sandbox Code Playgroud)\n一旦我这样称呼它,你能告诉我它是如何工作的吗:
\nmyFunction()\nRun Code Online (Sandbox Code Playgroud)\ncaller当参数实际上未定义时,为什么我没有 \xe2\x80\x99t 收到错误?
另一方面,如果我省略它并编写如下代码:
\nconst myFunction = () => {\n return function () {\n firstFuctnion();\n secondFunction();\n };\n };\nRun Code Online (Sandbox Code Playgroud)\n这两个函数firstFuction()和secondFunction()\xe2\x80\x99t 被执行。那么,caller\xe2\x80\x8a\xe2\x80\x94\xe2\x80\x8a 到底是如何调用\xe2\x80\x80\x99\xe2\x80\x8a\xe2\x80\x94\xe2\x80\ x8a 工作吗?
对于那些可能想查看完整功能代码的人:
\nconst myFunction = () => {\n return function (caller) {\n caller(firstFuctnion());\n caller(secondFunction());\n };\n};\nRun Code Online (Sandbox Code Playgroud)\r\n我不明白这部分。那dispatch实际上是做什么的。它没有作为参数传递,也没有在任何地方定义它是什么。是功能吗?我可以whatever在那里写。
const fetchUsers = () => {\n return function (dispatch) {\n dispatch(fetchUsersRequest());\n axios\n .get("https://jsonplaceholder.typicode.com/users")\n .then((response) => {\n // response.data is the users\n const users = response.data.map((user) => user.id);\n dispatch(fetchUsersSuccess(users));\n })\n .catch((error) => {\n // error.message is the error message\n dispatch(fetchUsersFailure(error.message));\n });\nRun Code Online (Sandbox Code Playgroud)\n};\n};
\nmyFunction()让\xe2\x80\x99s考虑此代码的简化版本。\n在您为问题添加一些重要的上下文之前(实际正在使用的事实,以及它\xe2\x80\x99s如何使用),我是\xe2 \x80\x99 不太确定你的困惑在哪里,所以这个答案首先对回调、高阶函数和柯里化进行一般解释。
首先让\xe2\x80\x99s 将 变成function箭头函数,这样代码读起来更直观。\n它们之间是有区别的,但让\xe2\x80\x99s 暂时忽略它们。\n让\ xe2\x80\x99s 也重命名myFunction为outer,因此我们知道我们\xe2\x80\x99正在谈论哪个函数。
const outer = () => {\n return (caller) => {\n caller(something);\n };\n};\nRun Code Online (Sandbox Code Playgroud)\nouter是一个函数。\nouter()也是一个函数;这意味着函数的返回值outer本身就是一个函数。
由于outer是一个返回函数 的函数,因此这会生成outer一个高阶函数 (HOF)(根据 HOF 的两个定义之一)1。
为了明确起见,您可以使用另一个变量来引用返回的函数:
\nconst inner = outer();\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n
caller当参数实际上未定义时,为什么我没有 \xe2\x80\x99t 收到错误?
那\xe2\x80\x99是一个奇怪的问题;当outer()被调用时,\xe2\x80\x99 还没有触及caller。\n只有调用inner才会触及。
问问自己:为什么你没有得到一个错误,a并且b没有在这里定义?2
const sum = (a, b) => a + b;\n\nsum;\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x99 是对的:sum甚至没有调用 \xe2\x80\x99!\n就像outer()没有调用 \xe2\x80\x99 一样。
即使更进一步,这也不会\xe2\x80\x99t 抛出错误,即使somethingUndefined任何地方没有定义并且不能在任何地方设置,这也不会抛出错误。\n(但是你会收到 linter 警告。)
const someFunction = () => somethingUndefined;\n\nsomeFunction;\nRun Code Online (Sandbox Code Playgroud)\n在这个常见的 HOF 示例中,尽管没有在分配给的b点定义,为什么在这里没有得到错误add(5)addFive?
const add = (a) => {\n return (b) => a + b;\n};\n// Or more simply:\n// const add = (a) => (b) => a + b;\n\nconst addFive = add(5);\n\nconsole.log(addFive(3)); // Pints 8.\nRun Code Online (Sandbox Code Playgroud)\n因为需要的函数b,即addFive,还没有被调用。
如果你想因为caller没有定义而强制出错,你\xe2\x80\x99d必须调用实际需要caller定义的函数。有问题的功能是outer()!像任何其他函数一样,您可以使用():来调用它outer()()。现在你得到 aTypeError因为callerisn\xe2\x80\x99t 是一个函数。
这个 \xe2\x80\x9cdouble call\xe2\x80\x9d 被称为柯里化(currying)。
\n代码也可以像这样重写。\n唯一的区别是inner现在也可以在外部作用域outeris 中访问。\n请参阅JavaScript 中变量的作用域是什么?。
const inner = (caller) => {\n caller(something);\n};\nconst outer = () => inner;\nRun Code Online (Sandbox Code Playgroud)\ninner扮演返回函数 ( ) 的角色outer()。\n它将函数作为参数并用它something作为参数调用它。
outer只是一个返回该函数的函数inner,没有其他任何东西。\n它没有调用它,它没有\xe2\x80\x99t触及caller,它与 无关something。
outer()并且inner是相同的。
\n\n另一方面,如果我省略它并编写代码[不带
\ncaller],则这两个函数firstFuction()和secondFunction()\xe2\x80\x99t 将被执行。那么,caller\xe2\x80\x8a\xe2\x80\x94\xe2\x80\x8a 到底是如何调用\xe2\x80\x80\x99\xe2\x80\x8a\xe2\x80\x94\xe2\x80\ x8a 工作吗?
首先,让\xe2\x80\x99s修复语义:firstFuction()and secondFunction()are 函数调用。\n它们是否是函数,取决于firstFuctionandsecondFunction返回的内容。\n firstFuctionandsecondFunction 是函数(至少代码暗示它们是)。
更具体地说,请考虑alert:
alert是一个函数;你可以这样称呼它alert()。alert()不是一个函数;你不能这样称呼它alert()()。caller是一个回调函数。\n如果您caller从代码中省略,则myFunction()()正确的调用不会\xe2\x80\x99t 抛出错误,而只是调用firstFuction和secondFunction。
但回调的重点是将firstFuction和的结果传递secondFunction给函数caller。\n您必须自己提供该函数,例如 函数alert。
myFunction()(alert)调用内部函数,并将其传递alert给它。\n内部函数调用firstFuction和secondFunction,并将它们的结果传递给caller,我们指定为alert。
\n\n一旦我这样称呼它,你能告诉我它是如何工作的吗
\nmyFunction()?
很简单,这里什么也没发生。\nmyFunction返回一个函数,\xe2\x80\x99 就是它;该函数未进一步使用,因此被丢弃。
此代码中未演示高阶函数的一个关键方面:封装值。\n考虑以下代码:
\nconst add = (a) => {\n let count = 0;\n\n return (b) => {\n ++count;\n console.log(`The function to add ${a} to something else has been called ${count} time(s).`);\n\n return a + b\n };\n};\nRun Code Online (Sandbox Code Playgroud)\nadd并且工作方式与之前b类似,但现在,外部函数也需要一个参数,因此不会\xe2\x80\x99t帮助。\n调用该函数并将参数设置为。\n此外,调用内部返回函数,设置到并返回。myFunctioncalleradd()add(5)adda5add(5)(3)b38
但是,\xe2\x80\x99s 内部也有一些状态,add以名为 的变量的形式存在count。
const addFive = add(5);\n\nconsole.log(addFive(3)); // Prints 8.\n// But also logs: "The function to add 5 to something else has been called 1 time(s)."\n\nconsole.log(addFive(10)); // Prints 15.\n// But also logs: "The function to add 5 to something else has been called 2 time(s)."\nRun Code Online (Sandbox Code Playgroud)\ncount只能在内部访问outer(包括其中的任何函数);它是 \xe2\x80\x9cencapsulated\xe2\x80\x9d。\n这是隐藏某些只能在特定函数内部访问的状态的常见方法。
a实际上也封装在add(\xe2\x80\xa6内);a并且count具有相同的作用域,并且\xe2\x80\x99t彼此不同,只是a可以在调用时将其设置为参数add,而count不能。
然后,您\xe2\x80\x99ve 添加了更多上下文,其中调用看起来更像是这样:
\nsomeOtherFunction(myFunction())\nRun Code Online (Sandbox Code Playgroud)\n这与之前的情况不同,您刚刚编写了像 这样的调用myFunction()。\n现在,结果不会被丢弃,因为它被输入someOtherFunction(在原始代码中store.dispatch:)。
\n\n[
\ncaller] 没有作为参数传递,也没有在任何地方定义。
但现在的工作是使用适当的回调函数作为参数进行someOtherFunction调用。\n现在,您不需要自己传递该函数;相反,为您做。myFunction()someOtherFunction
将此与JavaScript 回调函数中的参数从哪里来进行比较?.\n如果您返回到sum前面的示例函数,那么您可以自己传递参数:
sum(1, 2);\nRun Code Online (Sandbox Code Playgroud)\n或者某些库或框架可以为您做到这一点:
\n// Library code\nconst doTheRightThing = (callback) => callback(1, 2);\nRun Code Online (Sandbox Code Playgroud)\n// Your code\ndoTheRightThing(sum);\nRun Code Online (Sandbox Code Playgroud)\n或内置(或主机定义)函数为您完成此操作:
\n[ 1, 2, 3 ].reduce(sum, 0);\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x99这些参数来自何处或从何处调用该函数并不重要。\n但它被调用,并且在某处使用正确的参数调用它。
\n1:高阶函数的两个定义是
\nouter符合第一个定义。\n outer()(独立且巧合地)符合第二个定义。
2:好的,当然,sum()也不会抛出错误,但是a和b仍然会是undefined,每个。undefined + undefined具有不\xe2\x80\x99t 导致错误的语义,但希望您明白这一点:在原始代码中,只会因为\xe2\x80\x99t 不可能而myFunction()()抛出错误。undefined(firstFunction())罪魁祸首是同一个:caller是undefined。
| 归档时间: |
|
| 查看次数: |
612 次 |
| 最近记录: |