0

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.

3
  • Maybe stackoverflow.com/questions/9779624/… is what you're looking for.
    – fblundun
    Commented Nov 28, 2020 at 23:38
  • Your original question title had Design Patterns in it - from that perspective you are attempting to create multiple inheritance in a language that does not support it. I don't understand why a proxy wouldn't work. Commented Nov 29, 2020 at 0:26
  • Looking at the proxy design pattern example from another website, the functions were just hardcoded. Which didn't show me how to dynamically pass functions through. The stack overflow question @fblundun linked was what I had in mind. I didn't know that proxy object existed.
    – Steven
    Commented Nov 30, 2020 at 16:12

2 Answers 2

1

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();
1
  • Great idea! I didn't think about that.
    – Steven
    Commented Nov 29, 2020 at 12:08
0

Addressing this: "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."

It is possible you missed checking for the 'undefined' method of the proxied class. In the code below note target[prop] === undefined - this check determines if the dynamic method exists on the target. If not, then look at the prop and call the method from the embedded object.

If you don't want to enumerate the methods from the embedded object, you can introspect them to find the object containing the method (not shown here).

This should demonstrate that a Proxy object can, indeed be used to accomplish your goal.

function Engine() {
  this.start = () => {
    console.log('started');
  }
}

function Tire() {
  this.getWidth = () => {
    console.log('got width');
  }
}

function Car() {
  this.tire = new Tire();
  this.engine = new Engine();
}

const carProxy = {
  get: function(target, prop, receiver) {
    if (target[prop] === undefined) {
      if (prop === "getWidth") {
        console.log('getting tire width');
        return target.tire.getWidth;
      } else if (prop === "start") {
        console.log('starting');
        return target.engine.start;
      } else {
        return () => {
          console.log('Undefined function');
        }
      }
    }
  }
};
const target = new Car()
const car = new Proxy(target, carProxy);
car.start();
car.getWidth();

2
  • Thanks for your reply but I was looking to do this dynamically as opposed to hard coding the function calls.
    – Steven
    Commented Nov 29, 2020 at 12:09
  • Right, that was my comment about introspecting the target object. You can find the missing method in one of the encapsulated objects and call it that way. I just didn't include that code for simplicities sake. Commented Nov 29, 2020 at 13:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.