问题
I am reading Eloquent Javascript and am having a difficult time understand the example below. Would anyone be able to do a line by line type explanation? Specifically, I'm confused as to why the first loop is starting at one, and why the push method is being used on both knownArgs and arguments. I know that this is related to "partial application", but would like a more detailed explanation of what exactly is happening line by line.
var op = {
"+": function(a,b){return a + b;}
};
function partial(func) {
var knownArgs = arguments;
return function() {
var realArgs = [];
for (var i=1; i<knownArgs.length; i++)
realArgs.push(knownArgs[i]);
for (var i=0; i<arguments.length; i++)
realArgs.push(arguments[i]);
return func.apply(null, realArgs);
};
}
map(partial(op["+"], 1), [0, 2, 4, 6, 8, 10]);
回答1:
The knownArgs
variable keeps a copy of the value of arguments
as it was when partial()
was called. That call returns another function, and inside that code arguments
are a whole different list — they're the arguments passed to that returned function. In other words:
var p = partial(someFunction, "hello", "world");
When p()
is called, knownArgs
will be "hello" and "world" (well and someFunction
too but note that the first loop starts at 1). If the call to p()
looks like this:
p("how", "are", "you");
then it will first push "hello" and "world" onto the realArgs
list (from knownArgs
), and then the three parameters passed to p()
, from arguments
.
edit — step-by-step breakdown of how map(partial(op["+"], 1), [0, 2, 4, 6, 8, 10]);
is evaluated:
First,
op["+"]
has to be evaluated. I'm guessing it returns a function, probably something like this:function add(a, b) { return a + b; }
That "add" function and the value
1
are passed topartial()
. Thus insidepartial()
thearguments
pseudo-array looks like[ add, 1 ]
That is, the first parameter is the "add" function from
op["+"]
and the second is that value1
. The only thing thatpartial()
really does before returning the anonymous function is to savearguments
intoknownArgs
. That has to be done because the weirdarguments
pseudo-variable is always assigned a new value upon each and every function call. It's being preserved here so that the code in the anonymous function can access it later.Now, with the anonymous function returned from
partial()
and that array of even numbers, we callmap()
. That function probably looks something like this (I don't have the book):function map(fn, list) { var i, result = []; for (i = 0; i < list.length; ++i) { result.push( fn( list[i] ) ); } return result; }
Inside
map()
, then, the first parameter is the anonymous function returned from the earlier call topartial()
. What does that function do? Well, it combines the parameters from the originalpartial()
call — except the first one — with the parameters passed into it. Themap()
function only passes one parameter, so the resulting parameter list on each call to the anonymous function will be the value1
passed topartial()
and then, on each iteration, a different even number from the list.
A simpler example would be to consider what happens when you call:
partial(op["+"], 1)(2);
That is, if you call partial()
and then immediately use its return value (the anonymous function). The effect will be the same as calling:
add(1, 2);
回答2:
The first loop starts at one instead of zero because knownArgs[0]
contains the function, not its argument.
push
appends a single element to an array. It's a fairly common way to build an array.
var realArgs = [];
for (var i=1; i<knownArgs.length; i++)
realArgs.push(knownArgs[i]);
for (var i=0; i<arguments.length; i++)
realArgs.push(arguments[i]);
will create a new array concatenated from knownArgs
and arguments
. knownArgs
holds the curried arguments and the function (which is not appended to realArgs
), and arguments
are the arguments supplied to the function when it's being called.
来源:https://stackoverflow.com/questions/13335600/partial-application-eloquent-javascript