skip to Main Content

Given this JavaScript object, I want to access their nested properties via dynamic method starting with ‘get’ + a CamelCased attribute name (of course the attribute must be defined in the inital object)

As far as I know, this can be achieved by using a Proxy object + recursion, but I need your input anyway.

Best regards!

function Order() {
    this.no = 'n1234';
    this.info = {
        customer: {
            ID: 'c1234'
            address: {
                //...
                shiping: {
                    // ...
                }
            }
        }
    }
}

var order = new Order();

// The expected result should be:
// order.no = order.getNo()
// order.info = order.getInfo()
// order.info.customer or order.info.getCustomer() or order.getInfo().customer or order.getInfo().getCustomer()
// and so on for all nested attributes

This is the snippet I prepared, but it doesn’t seem to work for nested properties.

function createProxy(obj) {
  return new Proxy(obj, {
    get(target, prop) {
      if (typeof target[prop] === 'object' && target[prop] !== null) {
        return createProxy(target[prop]);
      }
      if (prop.startsWith('get')) {
        const propName = prop.charAt(3).toLowerCase() + prop.slice(4);
        if (target[propName] !== undefined) {
          return () => target[propName];
        }
      }
      return target[prop];
    },
  });
}

function Order() {
  const properties = {
    no: 'n1234',
    info: {
      customer: {
        ID: 'c1234'
      }
    }
  };

  return createProxy(properties);
}

var order = new Order();

// order.getInfo().customer - { ID: 'c1234' }
// order.getInfo().getCustomer() - TypeError: order.getInfo().getCustomer is not a function"

2

Answers


  1. Chosen as BEST ANSWER

    Here is the working solution. Thanks to @Barmar and Alexander Nenashev

    /**
     * @param {Object} obj
     * @returns {Proxy} obj
     */
    function createProxy(obj) {
        return new Proxy(obj, {
            get(target, prop) {
                function out() {
                    if (Object.getPrototypeOf(target[prop]) === Object.prototype) {
                        return createProxy(target[prop]);
                    } else {
                        return target[prop];
                    }
                }
    
                if (!prop.startsWith('get')) {
                    return out();
                }
    
                var property = prop[3] + prop.slice(4);
    
                if (property.valueOf().toUpperCase() === property.valueOf()) {
                    prop = property;
                    return out;
                } else {
                    prop = prop[3].toLowerCase() + prop.slice(4);
                    return out
                }
            },
        });
    }
    
    function Order() {
        this.no = 'n1234';
        this.info = {
            customer: {
                ID: 'c1234',
                address: {
                    shipping: {
                        ID: 's4354654'
                    }
                }
            }
        }
        
        return createProxy(this);
    }
    
    var order = new Order();
    
    console.log(order.no) // "n1234"
    console.log(order.getNo()) // "n1234"
    console.log(order.info.getCustomer().getID()) // "c1234"
    console.log(order.getInfo().customer.ID) // "c1234"
    console.log(order.info.customer.getAddress().getShipping().ID) // "s4354654"
    console.log(order.getInfo().getCustomer().address.getShipping().getID()) // "s4354654"


  2. Some tweaks would help, the main is to return a proxy from getXXX() calls too:

    const createProxy = (obj) => new Proxy(obj, {
      get(target, prop) {
        const out = () => target[prop]?.__proto__ === Object.prototype ? createProxy(target[prop]) : target[prop];
        return prop.startsWith?.('get') && (prop = prop[3].toLowerCase() + prop.slice(4)) ? out : out();
      },
    });
    
    function Order() {
      const properties = {
        no: 'n1234',
        info: {
          customer: {
            ID: 'c1234',
            title: 'Bad customer'
          }
        }
      };
    
      return createProxy(properties);
    }
    
    var order = new Order();
    
    console.log(order.getInfo());
    console.log(order.getInfo().getCustomer().getTitle());
    console.log(order.info.getCustomer().ID);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search