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"); }]
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.