The Partial Function Application in JavaScript / Page 2 | WebReference

The Partial Function Application in JavaScript / Page 2


[previous] [next]

The Partial Function Application in JavaScript [con't]

Obtaining a Result from the Curry Function

The curry() function above always returns a function with pre-applied arguments. Sometimes it's more desirable to return the function result once all the parameters have been received. In order to do that, the currying function must know how many arguments to expect. This can be accomplished in one of two ways: You can either pass the number as an argument - something like aFunction.curryToResult(3) - or you can assign the parameter names in the function signature as you normally would - e.g.: aFunction(a, b, c).curryToResult(). In the curryToResult() function below, the line numberOfExpectedArguments = numberOfExpectedArguments || this.length; tests for the parameter. The this.length property is used by default and refers to the function's arguments length. The other difference is in the return function. Here, it checks the argument's length against the numberOfExpectedArguments. Once they've all been passed, it applies the method. Otherwise, it calls the original curry() function, passing the anonymous function using the arguments.callee property:

Using the curryToResult() function would be exactly the same as the curry() function. Apply it to your function and call it with whatever number of arguments you wish:

A More Elaborate Bind Function

Passing pre-applied variables to the function via the arguments list works well in most circumstances, but in situations where a function is called numerous times, such as in a loop, it can become inefficient. The bindWithGetters() function sets the pre-applied variables once by creating public getter methods within the scope of the function on which it's applied, thus giving us the best of both worlds: accessibility and safety. Getter functions can be parsed from the other parameters using their name. After removing the object from the arguments collection, a for loop iterates through each argument, looking for functions called "generateGetter." These are then executed using the Function.call() function and the resulting getters are stored in the getter variable. To make them publicly accessible, they are appended as a property to the bound function. Remaining arguments are stored in the newArguments variable. Finally, a new function is returned which calls the original function with the original arguments and any additional ones concatenated together:

There a couple of helper functions that are called from the bindWithGetters() function. The first is the getName() function. It's meant to be a member of the Function object, but appending it to the Object.prototype gives us the ability to call it on all the arguments. It even works on primitive types, such as: booleans, numbers and strings because the JavaScript parser will promote these to their Object wrappers in order to call the function. Hence, booleans becomes Booleans, numbers becomes Numbers and strings becomes Strings. Validation inside the function returns a blank string for any argument that isn't of type "function", so that the test arg.getName() == 'generateGetter' will return false without an error being thrown. The Function.name property is only supported in JavaScript 1.5, so the last resort is to parse the function name, represented by the this pointer, from its signature using a regular expression:

The second helper function, generateGetter(), is another example of partial application. It goes three function levels deep by the time it returns the getter, which is itself a function! Like getName() above, it's also a member of the Object.prototype. While we were really only interested in functions there, we now legitimately want to accept all data types. The first level of partial application happens when the this pointer is stored for later use. In fact, we must store it or it will be replaced by a function object by the time we use it. At this point, the function merely returns a generic version of itself, which includes code to set the getterName. This is the function called in the bindWithGetters() function. To return the getter function, a new Function is created so that the getterName can be used as the function name. An inline function is once again put to good use so that the getter's return value is passed directly to the inner function:

To put our bindWithGetters() function to the test, we'll create a function that displays the bound arguments, along with the two getters, apply the bindWithGetters() function to it, and then call it. The object that the arguments will be bound to is a basic JavaScript object that we'll create using the new keyword. To identify it, we'll give it a name property. Next we'll apply bindWithGetters() to a function called testBindWithGettersFunction(), passing in our object, along with a number of other arguments. Two of these are to generate public getter methods: one for a string, another for a boolean. To create the getters, we call the generateGetter() function on the variable and pass in the variable name — e.g.: 'a string'.generateGetter('test'). To call the generateGetter() function on a boolean, we have to enclose it in parentheses. This will act like the quotes around the string to promote it to a Boolean object so that our generateGetter() function can be applied to it. Finally we call the bound function with a new argument, to make sure it's appended to the end of the pre-applied arguments collection:


[previous] [next]