Yes, you've written that partial
function exactly right.
I would avoid confusing yourself by using the term "callback" here. That word is usually used in a different context: to mean a routine which is called when something is done, or called for each element of an array by forEach
, for example. Here, what you are passing in is simply an underlying function, which will be called along with an extra specified parameter when the returned function is called. You can also return the function directly so just
var partial = function(fn, firstName) {
return function(lastName) {
return fn(firstName, lastName);
};
}
Is there any other way to refactor this callback so that it's cleaner?
Not really, other than as mentioned above. However, it could be made more general (see below).
I wasn't sure if I needed to create a new innerFunction
but when I did I finally got the behavior to work as intended.
By definition, partial
needs to return a function. That's its purpose. So yes, you have to create the function you are going to return. You could create it as a separate named function and then return it, as you did, or create it right in the return statement, as above.
Is my reasoning in the comments to the code accurate?
Not entirely:
I declared an inner function in order to create a closure of the variable lastName
but in fact this function is closing over firstName
, the variable from the outer scope.
The closure is completed (or is it only then created?) by returning the function argument named callback taking firstName and lastName as argument
Different people have different ideas about the precise meaning of closure. Some would say that merely defining a function using a variable from an outer scope constitutes a closure. Others would say that it is not a closure, or at least it doesn't make sense to call it a closure, unless the function is "exported" (returned) for use from outside, as you are doing.
Would somebody mind stepping through my code and further explaining what is happening, why callback
is returned from innerFunction
and why partial
returns innerFunction
instead of callback
?
callback
is not being returned from innerFunction
; the result of invoking it is. That's exactly how you need it to work: you want the function returned by partial
to invoke the function you originally passed in. Returning callback
directly from partial
would not accomplish anything; you would just be returning the function you passed in.
So the overall flow is:
You have some function like fullName
, and you want to create another function that has the first argument "already filled in".
Define the function partial
which takes a function to fill in the argument for, and the argument to fill in.
partial
"remembers" the function to be called and the argument to fill in passed to it. It returns a function (which is what you want)
You call the partial function returned from partial
, which calls the original function with the pre-filled argument and one more passed into that function. That function (your innerFunction
) can "see" the function to call (what you call callback
) and the argument to fill in because it closes over them (it's a closure accessing those variables from the outer scope.
However, your partial is a bit limited. For one thing, it only handles one pre-filled argument. You might want to handle more. Also, it doesn't know how to pass through this
to the innerFunction
. You can solve those kinds of problems by doing:
function partial(fn, ...prefilledArgs) {
return function(...additionalArgs) {
return fn.call(this, ...prefilledArgs, ...additionalArgs);
};
}
In the above, I've used the new ES6 "spread parameters" feature, because it's easier to read and write. In ES5, you need to use array functions to splice together the pre-filled arguments and additional arguments, which is not too much fun, as follows:
function partial(fn)
var prefilledArgs = Array.prototype.slice.call(arguments, 1);
return function() {
var additionalArgs = Array.prototype.slice.call(arguments);
return fn.apply(this, prefilledArgs.concat(additionalArgs));
};
}
In the above, we "remember" the pre-filled arguments and assign them to the variable prefilledArgs
, by removing the first element (fn
) of the arguments pseudo-array using slice
. Then, inside the inner function, we concatenate the pre-filled arguments and the additional arguments, and pass the whole list to the original function using apply
, which is the way to call a function when you have the arguments in an array.