Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
553 views
in Technique[技术] by (71.8m points)

javascript - TS / JS: Overwrite a function and call original function within

I'd like to know if there's a way to modify a function in TypeScript and access the original function within. This is an example of how I got it to work:

let obj = {
  shout: () => {
    console.log("AHHHHH!");
  },
};

let s = obj.shout;

obj.shout = () => {
  console.log("I'm going to shout.");
  s();
};

obj.shout(); //-> "I'm going to shout", "AHHHHH!"

This way I was able to add a warning to my shout function whenever it's called - but I feel like that's an ugly way to do it, so I wonder if there's a better way.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The OP's approach is the most intuitive/natural one. With JavaScript applications one sometimes is in need of intercepting and/or modifying the control flow of functionality one does not own or is, for other reasons, not allowed to touch.

For exactly this scenario there is no other way than to preserve and alter such logic by wrapping their original implementation. This ability is not unique to JavaScript. There is quite a history of programming languages that enable Metaprogramming via Reflection and Self-Modification.

Of cause one could/should provide bulletproof but handy abstractions for all the possibly modifier use cases that one can think of ... starting right away with the OP's use case that is the most obvious and easiest to implement one, which could be handled by e.g a before modifier ...

const obj = {
  shout: function (...args) {

    console.log('AHHHHH!');

    console.log('args : ', args);
    console.log('this is me : ', this);
  }
};
obj.shout();


obj.shout = obj.shout.before(function () {

  console.log("I'm going to shout.");

}, obj);

obj.shout('test of "before" modifier');


const anotherOne = {
  name: 'anotherOne'
};
obj.shout.call(anotherOne, 'delegation and self reflection');


/*
console.log(
  'Object.getOwnPropertyDescriptors(Function.prototype) :',
  Object.getOwnPropertyDescriptors(Function.prototype)
);
*/
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  (function (Function) {

    const fctPrototype = Function.prototype;
    const FUNCTION_TYPE = (typeof Function);

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

    function before/*Modifier*/(handler, target) {
      target = getSanitizedTarget(target);

      const proceed = this;
      return (

        isFunction(handler) &&
        isFunction(proceed) &&

        function () {
          const context = target || getSanitizedTarget(this);
          const args = arguments;

        //handler.apply(context, args);
          handler.call(context, args);

          return proceed.apply(context, args);
        }

      ) || proceed;
    }
    // before.toString = () => 'before() { [native code] }';

    Object.defineProperty(fctPrototype, 'before', {
      configurable: true,
      writable: true,
      value: before/*Modifier*/ 
    });

  }(Function));
</script>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...