Home > Mobile >  Dynamic Function Watcher in JS
Dynamic Function Watcher in JS

Time:10-10

I'm working on a pet project, a little front-end library for students. It reads variables/code in a JS file and tests it, outputting some panels. The code itself roughly follows the Jest framework.

My problem is that I'm trying to create a function that watches the execution of other functions, counts them, and lets me access the count.

function watchFunction(funcName){
    let originalFunction = window[funcName];
    let counter = 0;
    
    // Wrap the function, counts when called
    window[funcName] = function(...args){
        console.log("watching");
        counter  ;
        return originalFunction(...args);
    }

    return {
        getCount: () => {return counter},
        reset: () => {
            // Unwrap the function
            window[funcName] = originalFunction
        }
    }
}

This seems to work for methods like Number() or parseInt(), but I don't know how I would go about accessing methods like Math.floor(), or prototype methods like Array.prototype.map().

I've tried passing in the function reference instead of using window["funcNameString"], but that doesn't seem to work.

Does anyone have suggestions or tips for wrapping functions or watching functions like this?

CodePudding user response:

Do you mean a method of an instance or object? One way is to create a new function. e.g

function WatchInstanceMethods(instance, functionName){
let originalFunction = window[instance][funcName];
let counter = 0;
   window[instance][functionName] = function(...args){
        console.log("watching");
        counter  ;
        return originalFunction(...args);
    }
     return {
        getCount: () => {return counter},
        reset: () => {
            // Unwrap the function
            window[funcName] = originalFunction
        }
    }

} 

although adding support for chaining methods will get difficult with more nested methods but you can pass a string for functionName name and split it to have each layer of calling instance for function and repeat the logic above.

CodePudding user response:

Is that what you want? I can also write a block for this function so that it determines whether an object has been passed in or a string. If string -> run this function on window as a property "objectThatStoresFunction".

I've tried playing around with the Function.prototype, but it doesn't really work. So the function turned out a bit more complex.

function watchFunction(objectThatStoresFunction, functionName) {
    let counter = 0;
    
    const originalFunction = objectThatStoresFunction[functionName];
    
    objectThatStoresFunction[functionName] = (...args) => {
        console.log("watching");
        counter  = 1;
        return originalFunction(...args);
    }
    
    return {
        getCount: () => {return counter}
    }
}




const mathRoundWatcher = watchFunction(Math, 'round');

// 0
console.log(mathRoundWatcher.getCount());

Math.round(99666.9999999);

// 1
console.log(mathRoundWatcher.getCount());

Math.round(999999999.99);

// 2
console.log(mathRoundWatcher.getCount());

Works with window properties too

    function watchFunction(objectThatStoresFunction, functionName, optionalOriginalFunction) {
      if (optionalOriginalFunction) {
        objectThatStoresFunction = this.window;
        functionName = optionalOriginalFunction.name;
        console.log('function name', functionName);
      }
        let counter = 0;
        
        const originalFunction = objectThatStoresFunction[functionName] ?? optionalOriginalFunction;
        
      
        
        objectThatStoresFunction[functionName] = (...args) => {
            counter  = 1;
            return originalFunction(...args);
        }
        
        return {
            reset: () => objectThatStoresFunction[functionName] = originalFunction,
            getCount: () => {return counter}
        }
    }




    const mathRoundWatcher = watchFunction(Math, 'round');

    // 0
    console.log(mathRoundWatcher.getCount());

    Math.round(99666.9999999);

    // 1
    console.log(mathRoundWatcher.getCount());

    Math.round(999999999.99);

    // 2
    console.log(mathRoundWatcher.getCount());








    const alertWatcher = watchFunction(null, null, window.alert);

    // 0
    console.log(alertWatcher.getCount());

    window.alert('1');

    // 1
    
    console.log(alertWatcher.getCount());
  
    alert('2')

    // 2
    console.log(alertWatcher.getCount());

  • Related