So, you can do this:
window.alert=function(a) {
return function(b) {
a(b+'!')
}
}(window.alert)
Now suddenly alert('Hi')
will alert Hi!
. So, the window's alert function has been successfully modified. Fun.
Now the problem I'm having is applying this same concept to HTML5's CanvasRenderingContext2D
(canvas). I'm not sure if prototype
is the problem or if it's something else, but it's returning an "illegal invocation" error when I try to call the newly modified lineTo function.
CanvasRenderingContext2D.prototype.lineTo=function(a) {
return function(b,c) {
a(b,c)
return this
}
}(CanvasRenderingContext2D.prototype.lineTo)
Can anyone get this to work or at least find out what exactly is causing it?
Also, in case you're wondering, my reason for wanting to do this is to create chaining with canvas functions (e.g. context.lineTo(10,15).lineTo(20,15).lineTo(20,20)
).
First of all, mandatory warning against modifying host objects.
Now that you know what you're getting into, here's the problem with your snippet:
The new function that's assigned to CanvasRenderingContext2D.prototype.lineTo
calls old function simply as a(b, c)
. When a function is called like this — a(b, c)
— also known as "called as function", it's executed with this
being global object.
So context.lineTo(10, 15)
will now execute old lineTo
function (aliased under a
) with this
being Global Object rather than context
. When lineTo
doesn't have context
to operate upon, it obviously can't do much, hence the error.
How to fix this?
Well we can call function with proper this
value:
CanvasRenderingContext2D.prototype.lineTo = function(a) {
return function(b,c) {
a.call(this, b, c);
return this;
};
}(CanvasRenderingContext2D.prototype.lineTo);
Notice a.call(this, b, c)
which calls a
function with correct this
.