Search code examples
javascriptdesign-patternssoftware-design

How to intercept a function call in JavaScript to grab the function call name


I wasn't sure how to word the title so I will go into more detail.

What I want to do is have some object called car.

The object car contains two objects called tire and engine.

What I want to happen is be able to say,

car.start();

Then I want the car object to be able to check both tire and engine to see if it contains a function with that name then call it.

So in summary

I want to be able to call an object and have that object called pass it onto whoever implemented that function call.

I looked at the proxy pattern but I don't see how I can dynamically have function calls passed on from an object to a nested object.

Any ideas would be appreciated. Thanks!

Example Code

function engine() {
    return {
        start: () => console.log('start')
    }
}

function tire() {
    return {
        getWidth: () => console.log('get width')
    }
}

function car() {
    this.tire = new tire();
    this.engine = new engine();

    // Pass on function calls made to car over to tire or engine depending on who implemented that function call.
}

// This should print start.
car.start();

**PS. ** I know I can hard code the function calls and have it pass through but I am trying to do this dynamically so I don't have to declare every single function that can be called. So I want to do this dynamically.


Solution

  • Convert them to actual classes then copy properties from their prototypes:

    class Engine {
        start() {
            console.log("start");
        }
    }
    
    class Tire {
        getWidth() {
            console.log("get width");
        }
    }
    
    class Car {
        constructor() {
            this.tire = new Tire();
            this.engine = new Engine();
        }
    }
    
    for (const key of Object.getOwnPropertyNames(Engine.prototype)) {
        if (key !== "constructor") {
            Car.prototype[key] = function(...args) { return this.engine[key](...args); };
        }
    }
    
    for (const key of Object.getOwnPropertyNames(Tire.prototype)) {
        if (key !== "constructor") {
            Car.prototype[key] = function(...args) { return this.tire[key](...args); };
        }
    }
    
    const car = new Car();
    car.start();
    car.getWidth();