我正在阅读“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 ”转到第一个参数,“ 6 ”转到第二个参数?< / p>
有一行代码apply(null, args.concat(slice.apply(arguments)))
,为什么apply(null,...)
在这里?,将参数应用于空对象有什么意义?
答案 0 :(得分:6)
有两个地方使用'参数'。在最后两行代码中调用的方法中,是否“1”转到第一个参数,“6”转到第二个参数?
是的,1是外部函数arguments
的一部分,而6是内部函数中的arguments
。内部函数可以捕获闭包中的所有其他变量,除了arguments
和this
,它们在函数内部具有特殊含义,因此不是该闭包的一部分。因此,that
和args
被捕获,但不是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