javascript'curry',需要对此代码进行一些解释

时间:2011-03-28 08:48:41

标签: javascript

我正在阅读“JavaScript-The Good Parts”一书,在第4.14章Curry中,本书给出了以下例子:

Function.method('curry', function(){
    var slice = Array.prototype.slice,
        args = slice.apply(arguments), //1st-arguments
        that=this;

    return function(){
       return that.apply(null, args.concat(slice.apply(arguments))); //2nd-arguments
    }
})

var add1=add.curry(1);
document.writeln(add1(6)); // 7

我对这段代码有两个问题:

  1. 有两个地方使用'参数'。在最后两行代码中调用的方法中,是否“ 1 ”转到第一个参数,“ 6 ”转到第二个参数?< / p>

  2. 有一行代码apply(null, args.concat(slice.apply(arguments))),为什么apply(null,...)在这里?,将参数应用于空对象有什么意义?

2 个答案:

答案 0 :(得分:6)

  

有两个地方使用'参数'。在最后两行代码中调用的方法中,是否“1”转到第一个参数,“6”转到第二个参数?

是的,1是外部函数arguments的一部分,而6是内部函数中的arguments。内部函数可以捕获闭包中的所有其他变量,除了argumentsthis,它们在函数内部具有特殊含义,因此不是该闭包的一部分。因此,thatargs被捕获,但不是arguments

  

有一行代码应用(null,args.concat(slice.apply(arguments))),为什么它在这里应用(null,...)?将参数应用于a的意义是什么? null object?

调用具有空上下文的方法只会将this值设置为全局对象。在这种情况下,作者似乎并不关心那个背景是什么。

答案 1 :(得分:2)

这个例子对我来说也很棘手,因为我没有JavaScript的经验,所以我会尝试解释它,因为我希望向我解释。由于这个原因,它可能太明确了!

另外,在你开始之前,我建议你检查一下'闭包'部分(对我来说理解闭包,对这句话很有帮助):

“闭包是一种特殊的对象,它结合了两个东西:一个函数,以及创建该函数的环境。环境由创建闭包时在范围内的任何局部变量组成。 “。 (来自Mozilla开发人员网络) - Closures: Line by Line explanation of "Javascript: Good Parts" example?

现在关于咖喱的例子:

apply(this,arguments) - 此方法可以应用于函数来调用它,并将'this'变量和参数变量作为数组(参数)发送。

例如:

// JSON objects
var ob1 = { // first object
    a : 0,
    b : 0
};

var ob2 = { // the second one
    a : 0,
    b : 0
};

// a function that updates 'a' and 'b'
function update(newA, newB) {
    this.a = newA;
    this.b = newB;
}

// 'this' is equal with ob1 and arguments array is [10, 20]
update.apply(ob1, [10, 20]);

// the same as above, but 'this' is here ob2
update.apply(ob2, [30, 40]);

/* after update:
ob1 {
      a: 10,
      b: 20
    }
ob2 {
      a: 30,
      b: 40
    }
*/

现在,您已了解apply,您可能会问为什么在此示例中仅使用单个参数调用。

  args = slice.apply(arguments); 

函数'slice'接受一个数组和一些表示索引的参数,并仅与那些形成一个新数组。例如:

var anArray = ['red', 'green', 'black'];
var otherArray = anArray.slice(0); // after this line 'otherArray' will be ['red']
otherArray = anArray.slice(1,2); // 'otherArray' will be ['green','black'] 
// but what happens id you don't specify any indexes?
otherArray = anArray.slice();
// otherArray will be equal with ['red', 'green', 'black'], the same as 'anArray'
// it just makes a copy of it

所以,当它确实:

args = slice.apply(arguments)

与:

相同
args = slice.apply(/*this*/ arguments, /*arguments*/ undefined);

这几乎就是说:

args = arguments.slice(); // args will have all the elements the same as arguments

之所以这样做是因为args将是一个包含数组所有方法的数组,但是'arguments'没有任何方法。

“由于设计错误,参数实际上不是一个数组。它是一个类似于数组的对象。参数有一个长度属性,但缺少所有的数组方法。” (来自书)

让我们回顾一下,我们需要这两行:

   var slice = Array.prototype.slice;
   args = slice.apply(arguments);

只是为了让'参数'拥有特定于数组的所有方法。 在我们的例子中,我们需要'concat'方法,它接受两个数组并加入它们。

Function.method('curry', function(){
       var slice = Array.prototype.slice;
       args = slice.apply(arguments);
       that=this; // saves this (which will be a function)

       return function(){
    // 'that' will be the same as this from above
    // and is a function that we call it with the apply
          return that.apply(/*this*/null, /*arguments*/ args.concat(slice.apply(arguments))); 
   // 'this' was null, an arguments was a join between 'args' and 'arguments'
}
});

最后,您只需要了解将如何使用:

function add(a, b) {
    return a + b;
}

var add1 = add.curry(1); // add is function, and 'add.curry(1)' returns a function
    // that will have 'a' set as 1(one) and 'b' as undefined(not being set)

var sum = add1(6); // 7
// when you call add1(6), you actually call that function that was returned by
// the line add.curry(1), with 'b' equal with 6