henrybai henrybai - 27 days ago 15
Javascript Question

javascript and currying

I am reading through John Resig's Secrets of Javascript ninja and was trying out one of the examples on currying and parital functions. The code is as follows:

<html>
<body>
<button id="test">Click Me!</button>
</body>


<script type="text/javascript">
Function.prototype.curry = function() {
var fn = this,
args = Array.prototype.slice.call(arguments);

return function() {
return fn.apply(this, args.concat(
Array.prototype.slice.call(arguments)));
};
};


var elem = document.getElementById("test");
var bindClick = elem.addEventListener.curry("click");
bindClick(function(){ console.log("OK"); });
</script>
</html>


However, the following code seems to generate an error Uncaught TypeError: Illegal invocation on the apply function.

I cant seem to figure out the reason as it all seems to make sense.
bindClick
will return an anonymous function that calls the function
elem.addEventListener
with
window
as the function context (
this
) and the arguments will be
["click", function() {console.log("OK"); }]

Answer

The problem is that you've lost the context of the element. The addEventListener method has to be called on an element, but you're calling it on a function:

// Here, `this` refers to a function, not an element
return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));

You would need to pass in the element to your new function. For example:

Function.prototype.curry = function () {
    var fn = this,
    args = Array.prototype.slice.call(arguments);

     return function (context) {
         return fn.apply(
             context,
             args.concat(Array.prototype.slice.call(arguments, 1))
         );
     }; 
};

Here's a working example. Notice the addition of a context argument to the returned function, and also notice the addition of the second argument to the slice call - that's needed to remove the new context argument and only apply any following arguments.

Comments