Javascript 函数式编程-.bind.apply用于curry函数

Javascript 函数式编程-.bind.apply用于curry函数,javascript,functional-programming,currying,Javascript,Functional Programming,Currying,-说到咖喱,这个例子有一个简单的咖喱功能。除了最后一个块之外,我什么都懂 var curry = function (fn, fnLength) { fnLength = fnLength || fn.length; return function () { var suppliedArgs = Array.prototype.slice.call(arguments); if (suppliedArgs.length >= fn.lengt

-说到咖喱,这个例子有一个简单的咖喱功能。除了最后一个
块之外,我什么都懂

var curry = function (fn, fnLength) {
    fnLength = fnLength || fn.length;
    return function () {
        var suppliedArgs = Array.prototype.slice.call(arguments);
        if (suppliedArgs.length >= fn.length) {
            return fn.apply(this, suppliedArgs);
        } else if (!suppliedArgs.length) {
            return fn;
        } else {
            return curry(fn.bind.apply(fn, [this].concat(suppliedArgs)), fnLength - suppliedArgs.length);
       }
    };
};
如果提供的参数为
=
,请使用提供的参数调用函数

否则,如果
suppliedArgs.length
为falsy,则不执行任何操作返回原始函数

还有别的吗

  • 我认为递归调用函数
  • 我不明白。绑定。应用完成了什么
  • [这]
    只是在一个数组中,因为suppliedArgs.push不会返回数组吗

先看一下您如何称呼:

fun.bind(thisArg[,arg1[,arg2[,…]))

然后考虑如何使用:

乐趣。应用(thisArg,[argsArray])

因此对于
bind()
我们需要在函数上调用它,并给它多个参数(而不是数组),我们所拥有的只是一个参数数组(
suppliedArgs
,在代码中),那么我们怎么做呢?嗯,调用一个接受多个参数而不是一个数组参数的函数的主要方法是对函数使用
.apply()
。然后我们有了
fn.bind.apply(…某物…)

.apply()
的第一个参数是
值-在
.bind()
的情况下,该值必须是要绑定的函数(有关原因的解释,请参见下文)。因此
fn.bind.apply(fn,…)

然后,
.apply()
的第二个参数是所调用函数的所有参数的数组,在
.bind()
的情况下是
thisArg[,arg1[,arg2[,…]]
。因此,我们需要一个数组,第一个值是函数中
this
的值,后面是其他参数。这就是
[this].concat(suppliedArgs)
产生的结果

因此,整个
fn.apply.bind(fn[this].concat(suppliedArgs))
生成了一个正确绑定的函数,该函数将使用正确的
this
上下文为当前函数“prefilled”提供参数。然后,在对
curry()
的递归调用中,将生成的此函数作为
fn
参数传递,这反过来将以与顶级调用相同的方式生成另一个函数

总体效果是,无论何时调用由
curry()
创建的函数,如果未传递预期数量的参数,则将得到一个新函数,该函数将使用剩余数量的参数,或者使用正确传递的整个参数列表对原函数进行求值

e、 g

为什么不同的
thisArg
值? 关于这行代码,最令人困惑的可能是
.bind()
.apply()
中的
thisArg
的两个不同值

对于
.apply()
thisArg
是您希望
this
的值位于正在调用的
.apply()
函数中的值。e、 g.
myFunction.apply(myObj,['param1','param2'])
相当于
myObj.myFunction('param1','param2')

在这种特殊情况下,
.bind()
是在
fn
函数上执行的,因此我们希望
fn
.bind()
值,这样它就知道它正在创建绑定版本的函数

对于
.bind()
thisArg
是返回的绑定函数中
this
的值

在我们的例子中,我们希望返回一个绑定函数,该函数具有与当前相同的
this
值。换句话说,我们希望在新函数中正确地维护
这个
值,这样在创建新函数时就不会丢失该值,而在调用参数少于预期的curried函数时就会发生这种情况

如果我们没有正确维护
this
值,下面的示例将不会记录
this
的正确值。但通过维护它,将输出正确的值

var myObj = { 
    a: 1, 
    b: curry(function (a, b, c, d) { 
           console.log('this = ', this); 
           return a + b + c + d; 
       })
};
var c = myObj.b(1,1,1); // c is a function expecting 1 argument
c(1); // returns 4, and correctly logs "this = Object {a: 1, b: function}"
      // if "this" wasn't maintained, it would log the value of "this" as
      // the global window object.

最后一个else块是
curry
函数的主要和最重要部分,因为它是实际的行,承载了curry的逻辑

return curry(fn.bind.apply(fn, [this].concat(suppliedArgs)), fnLength - suppliedArgs.length);
这是返回需要上一个函数的n-1个参数的新函数的内容。为什么?它是多种事物的组合:


fn.bind.apply
只需在函数本身的上下文中调用函数,同时提供所需的参数(suppliedArgs)。请注意curry的下一个参数是fnLength-suppliedArgs.length,它将所需的参数减少为传递的参数。

让我们借助ES6进行解释。事情将变得更加明显

// Imagine we have the following code written in ES5
function fn(a, b, c) {
  console.log(a, b, c);
}

var arr = [1, 2, 3];
var funcWithBoundArguments = fn.bind.apply(fn, [null].concat(arr));
让我们将ES5转换为ES6代码

// ES6
function fn(a, b, c) { console.log(a, b, c) }

let arr = [1,2,3];

let funcWithBoundArguments = fn.bind(null, ...arr)
看到了吗?绑定函数时,必须显式枚举所有参数,如:

fn.bind(null, 1, 2, 3)
但是,如果我们事先不知道数组的内容,我们如何绑定它的内容呢

对,我们必须使用
.bind.apply()
其中:

  • apply
    的第一个参数是我们绑定的函数(
    fn
  • 第二个参数是一个数组,它获取我们将函数绑定到的上下文(作为数组的第一项),数组的其余项是我们将函数绑定到的参数(该数字是可变的)(
    fn

谢谢这真的很有帮助。我唯一不明白的是,为什么你想把
fn
设置为
thisArg
for
apply
,但是你实际上想
thisArg
设置为
bind
@diplosaurus的
thisArg
,我添加了额外的信息,希望能让你一目了然。好问题,不过,这也让我有点困惑,直到我仔细看了它,并以我描述的方式思考它。啊,这是有道理的,因为
app
fn.bind(null, 1, 2, 3)