在javascript中拦截函数调用

时间:2018-03-06 08:39:20

标签: javascript proxy hook function-composition modifier

我很感激,如果有人能告诉我如何拦截javascript中的函数调用。 我知道可以使用代理。

例如,我尝试使用下面的代码来拦截它,但现在我想拦截toDataURL()。为了调用toDataURL,你需要首先创建一个canvas元素。所以,现在我想知道如何定义代理来拦截toDataURL()

拦截它的示例代码:

window.x = 0;
    let calls = (function(){
        let canvas = document.createElement('canvas');
        let fun = canvas.toDataURL;
        canvas.toDataURL = function(){       
            window.x++;         
            return fun.apply(document, arguments);
        }
        return ()=>calls;
    })();

1 个答案:

答案 0 :(得分:0)

虽然总是应该有一个很好的理由来修改标准类型的标准方法,但JS中方法修改的基本方法是包装。有人甚至可能会考虑标准化Function.prototype[before|after|around|afterThrowing|afterFinally]。然后修改任何给定的方法或函数将像下一个提供的示例一样简单,也可能是OP正在寻找的答案......

(function (Function) {
  var
    isFunction = function (type) {
      return (
           (typeof type == "function")
        && (typeof type.call == "function")
        && (typeof type.apply == "function")
      );
    },
    getSanitizedTarget = function (target) {
      return ((target != null) && target) || null;
    };

  Function.prototype.before = function (handler, target) { // before
    target = getSanitizedTarget(target);
    var proceed = this ;

    return (isFunction(handler) && isFunction(proceed) && function () {
      var args = arguments;

      handler.call((target || this), args);
      return proceed.apply((target || this), args);

    }) || proceed;
  };
  Function.prototype.after = function (handler, target) { // afterReturning
    target = getSanitizedTarget(target);
    var proceed = this ;

    return (isFunction(handler) && isFunction(proceed) && function () {
      var ret, args = arguments;

      ret = proceed.apply((target || this), args);
      handler.call((target || this), ret, args);

      return ret;

    }) || proceed;
  };
  Function.prototype.around = function (handler, target) { // around
    target = getSanitizedTarget(target);

    var proceed = this ;
    return (isFunction(handler) && isFunction(proceed) && function () {

      return handler.call((target || this), proceed, handler, arguments);

    }) || proceed;
  };
}(Function));


function modifyCanvasToDataUrlAfter(returnValue, thisArgs) {
  console.log('modifyCanvasToDataUrlAfter :: thisArgs : ', thisArgs);
  console.log('modifyCanvasToDataUrlAfter :: returnValue : ', returnValue);
}
HTMLCanvasElement.prototype.toDataURL = HTMLCanvasElement.prototype.toDataURL.after(modifyCanvasToDataUrlAfter);


var elmToJpgLow = document.getElementById('canvasToLowResolutionJpg');
var elmToJpgMedium = document.getElementById('canvasToMediumResolutionJpg');

console.log("elmToJpgLow.toDataURL('image/jpeg', 0.1) : ", elmToJpgLow.toDataURL('image/jpeg', 0.1));
console.log('elmToJpgLow.toDataURL : ', elmToJpgLow.toDataURL);

console.log("elmToJpgMedium.toDataURL('image/jpeg', 0.1) : ", elmToJpgMedium.toDataURL('image/jpeg', 0.5));
console.log('elmToJpgMedium.toDataURL : ', elmToJpgMedium.toDataURL);
.as-console-wrapper { max-height: 100%!important; top: 0; }
<canvas id="canvasToLowResolutionJpg" width="5" height="5"></canvas>
<canvas id="canvasToMediumResolutionJpg" width="5" height="5"></canvas>

<强> 修改

基于Proxy的方法可能类似于以下提供的示例...

const canvasToDataUrlModifier = {
  apply: function(target, thisArg, argumentsList) {

    let returnValue = target.apply(thisArg, argumentsList);

    console.log('toDataUrlAfterModifier :: argumentsList : ', argumentsList);
    console.log('toDataUrlAfterModifier :: returnValue : ', returnValue);

    return returnValue;
  }
};

var elmToJpgLow = document.getElementById('canvasToLowResolutionJpg');
var elmToJpgMedium = document.getElementById('canvasToMediumResolutionJpg');

var proxyToJpgLow = new Proxy(elmToJpgLow.toDataURL, canvasToDataUrlModifier);
var proxyToJpgMedium = new Proxy(elmToJpgMedium.toDataURL, canvasToDataUrlModifier);

console.log("proxyToJpgLow.call(elmToJpgLow, 'image/jpeg', 0.1) : ", proxyToJpgLow.call(elmToJpgLow, 'image/jpeg', 0.1));

console.log("proxyToJpgMedium.call(elmToJpgMedium, 'image/jpeg', 0.5) : ", proxyToJpgMedium.call(elmToJpgMedium, 'image/jpeg', 0.5));
.as-console-wrapper { max-height: 100%!important; top: 0; }
<canvas id="canvasToLowResolutionJpg" width="5" height="5"></canvas>
<canvas id="canvasToMediumResolutionJpg" width="5" height="5"></canvas>