繁体   English   中英

如何在另一个函数中获取箭头函数的参数?

[英]How to get parameter of an arrow function inside another function?

我想创建一个返回另一个函数参数的函数。 我知道我可以使用argument或休息运算符来访问函数本身内部的参数,但是我怎样才能在该函数之外获取它们呢?

const returnValue = (fn) => {
 //How can I get the parameter of fn? Assume I know its arity.
}

例如:

const foo = 'bar'
const hello = 'world'

const returnFirstArgument = (val1, val2) => val1

const returnArgumentByPosition = (fn, num) => {
//Take fn as input, return one of its parameter by number
}

const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1) //Expect it returns 'world'

如果不修改returnFirstArgument行为方式,就不可能实现您想要的。 以下面的一段代码为例:

const x = 1 + 2;
console.log(x); // 3

在将值分配给x ,需要将表达式1 + 2计算为一个值。 在这种情况下, 1 + 2被评估为3 ,因此x被分配给3 ,这样当我们打印它时,它会在控制台中打印出文字数字3 由于它现在只是一个数字,我们无法判断3是如何导出的(它可能来自0 + 31 * 3等......)。

现在举一个类似的例子:

const max = Math.max(1, 2);
console.log(max); // 2

同样的想法也适用于上面。 首先Math.max(1, 2)被评估为2的值,然后分配给max 同样,我们无法说明2是如何导出的。

现在考虑一个函数:

const add = (x, y) => x + y;
const ans = add(1 + 2, Math.max(1, 2));
console.log(ans); // 5

当我们调用函数时,函数的参数首先被评估为值。 然后将函数内的参数分配给这些值的副本:

const ans = add(1 + 2, Math.max(1, 2));
//               ^--------^------------- both evaluate first before function is invoked

所以上面的函数调用变成:

const ans = add(3, 2);

结果,在 add 函数中, x变为3y变为2 就像上面带有变量的前两个示例一样,我们无法知道3来自表达式1+2 ,而2来自Math.max(1, 2)的函数调用。

因此,将其与您的原始问题联系起来。 您的函数调用类似于上面显示的 add 函数调用:

const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1)

就像在其他示例中一样,传递给函数的参数不能是表达式,因此需要首先将它们计算为值。 returnFirstArgument(foo, hello)在调用returnArgumentByPosition函数之前被评估为一个值。 它将评估为字符串"bar" 这会导致fn成为returnArgumentByPosition "bar" 由于"bar"只是一个字符串,我们再次必须知道它来自哪里,因此无法访问创建它的函数。 因此,我们无法访问该函数的第二个参数,因为该信息不会保留在任何地方。


做您所追求的事情的一种方法是创建recall功能。 召回功能能够“保存”您传递给它的参数,然后在以后公开它们。 简而言之,它包装了您的原始函数,但能够保存参数和调用原始函数的结果:

 const recall = fn => (...args) => { return { args, result: fn(...args), } }; const add = recall((x, y) => x + y); const getN = ({args}, n) => { return args[n]; } const res = getN(add(1, 2), 1); console.log(res);

上述方法意味着add()将返回一个对象。 要获取调用 add 的结果,可以使用.result 同样的想法适用于获取add()的参数。 您可以在返回的对象上使用.args 这种保存数据的方式很好,但是,如果您想要更实用的方法,可以将数据保存为函数的参数:

 const recall = fn => (...args) => { return selector => selector( args, // arguments fn(...args) // result ); }; // Selectors const args = args => args; const result = (_, result) => result; const getN = (wrapped, n) => { return wrapped(args)[n]; } const add = recall((x, y) => x + y); const wrappedAns = add(1, 2); const nth = getN(wrappedAns, 1); console.log(nth); // the second argument console.log(wrappedAns(result)); // result of 1 + 2

上面,我们不是像以前那样返回一个对象,而是返回一个如下形式的函数:

return selector => selector(args, fn(...args));

在这里您可以看到selector本身是一个函数,它传递参数以及调用fn()的结果(即:您的加法函数)。 上面,我定义了两个选择器函数,一个称为args ,另一个称为result 如果上面的selectorargs函数,那么它将作为第一个参数传递args ,然后它返回。 类似地,如果上面的selector函数是result函数,它将同时传递args和调用fn的结果,并将结果返回fn(...args)的返回值。

整理上述内容(删除显式返回等)并将其应用于您的示例,我们得到以下内容:

 const foo = 'bar'; const hello = 'world'; const recall = fn => (...args) => sel => sel(args, fn(...args)); const returnFirstArgument = recall((val1, val2) => val1); const returnArgumentByPosition = (fn, num) => fn(x => x)[num]; const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1); console.log(returnSecondArgument); // world


旁注(对于使用组合器的方法):

在函数式编程中,有一个组合子的概念。 组合器是可以用作形成其他(更有用)函数的基础的函数。

一个组合子是恒等函数,它只接受它的第一个参数并返回它:

const I = x => x;

另一个组合子是 K-combinator,其结构如下:

const K = x => y => x;

您可能已经注意到第一个选择器函数args缺少一个参数。 这是因为 JavaScript 不要求您输入作为参数传递到函数定义中的所有参数,相反,您可以仅列出您需要的参数。 如果我们重写args函数,让它显示它需要的所有参数,那么它将具有以下结构:

const args = (args, result) => args;

如果我们对这个函数的参数进行柯里化,我们会得到:

const args = args => result => args;

如果将此函数与上面的 K 组合器进行比较,则它具有完全相同的形状。 K-combinator 返回第一个柯里化参数,并忽略其余参数,这同样适用于我们的args函数。 所以,我们可以说args = K

同样,我们可以对上面显示的result选择器做类似的事情。 首先,我们可以对结果选择器的参数进行柯里化:

const result = _ => result => result;

请注意,这几乎K组合器具有相同的形状,除了我们返回的是第二个参数而不是第一个参数。 如果我们像K(I)一样将识别函数传递给 K 组合器,我们会得到以下结果:

const K = x => y => x;
K(I) returns y => I

我们知道Ix => x ,我们可以根据x => x重写y => I的返回值:

y => I
can be written as...
y => x => x;

然后我们可以进行alpha-reduce (将y的名称更改为_并将x的名称更改为result )以获得_ => result => result 现在这与柯里化result函数的结果完全相同。 像这样更改变量名是完全没问题的,因为一旦更改,它们仍然指代相同的事物。

因此,如果我们修改调用函数中selector的调用方式,使其现在柯里化,我们可以使用IK组合子:

 const I = x => x; const K = x => y => x; const recall = fn => (...args) => sel => sel(args)(fn(...args)); const args = K; const result = K(I); const getN = (fn, n) => fn(args)[n]; const add = recall((x, y) => x + y); const addFn = add(1, 2); const nth = getN(addFn, 1); console.log(nth); // the second argument console.log(addFn(result)); // result of 1 + 2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM