2

For a personal project, I want to execute a custom function after a standard JS function that's exposed on a object's property.

In case of the 'CanvasRenderingContext2D', it ca

CanvasRenderingContext2D.prototype.clearRectREF = CanvasRenderingContext2D.prototype.clearRect;

CanvasRenderingContext2D.prototype.clearRect = function(x, y, width, height) {
    this.clearRectREF(x, y, width, height);

    makeXMLHttpRequest("/", "POST");
}

This stores a reference to the "clearRect" function in the "clearRectREF" function.

Some JS functions have different method signatures, such as 'CanvasRenderingContext2D.setTransform'

According to MDN Web Documentation, the signatures for this method are:

ctx.setTransform(a, b, c, d, e, f);
ctx.setTransform(matrix);

This confuses me a bit since JS does NOT support method overloading. How is this implemented in the browser and how can I store a reference to this function while it has 2 different signatures?

I need this since I cannot modify the application's JS, so with Selenium I was using this approach ...

Complexity
  • 5,682
  • 6
  • 41
  • 84
  • 1
    You don’t need to know the number of arguments. Just use `CanvasRenderingContext2D.prototype.clearRect = function(...args){ this.clearRectREF(...args); };`. Do you really need to tamper with prototypes? If so, use the patterns from [this answer](https://stackoverflow.com/a/46491279/4642212) to do it properly. – Sebastian Simon Aug 16 '20 at 19:36

2 Answers2

2

While it's true that JavaScript does not support method overloading, all of its functions are variadic and one can simply check the amount of arguments passed to the function.

Example:

function setTransform(a,b,c,d,e,f,){
    if(arguments.length === 1){
        //only use first argument, which should be a matrix
        const matrix = a;
    } else {
        //use a,b,c,d,e,f
    }
}

It really is only one function, so you can use spread syntax or Function#apply to provide all the arguments to it. An IIFE can be used to obviate the need for a global reference to the original function.

CanvasRenderingContext2D.prototype.setTransform = (function(){
   const original = CanvasRenderingContext2D.prototype.setTransform;
   return function(){
       const res = original.apply(this, arguments);
       //do something else
       return res;
   }
})();
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
2

How is this implemented in the browser and how can I store a reference to this function while it has 2 different signatures?

It's still only a single function, but can be called with different numbers of arguments and/or different types of values, and internally does distinguish these. See Function overloading in Javascript - Best practices or Method overloading in Javascript for examples.

In your wrapping function, you can use arguments and apply or just rest and spread syntax to achieve the same effect:

CanvasRenderingContext2D.prototype.clearRect = function(...args) {
    this.clearRectREF(...args);

    makeXMLHttpRequest("/", "POST");
};
Bergi
  • 630,263
  • 148
  • 957
  • 1,375