0

I'm trying to reduce the amount of duplicate code i'm writing in JS objects. I have a methods that I want to use where almost nothing is changing except the target and I'd like to extract that out and somehow get the target through the objects property name. Hopefully the example I put together makes sense.

myObject = {
  d: {
    get: function(list, id) {
      // do stuff
    },
    prop1: {
      data: [],
      list: myObject.config.lists.prop1.guid,
      get: function(a,b) {
        myObject.d.get(a,b)
      }
    },

    // I want to write this once and use the object key ("prop2") as an argument
    prop2: {
      data: [],
      list: myObject.config.lists.prop2.guid,
      get: function(a,b) {
        myObject.d.get(a,b)
      }
    }
  }
};

Tried something like this but getting error "Cannot read prop 'spec' of undefined:"

myObject = {
  d: {
    get: function(list, id) {
      // do stuff
    }
  },

  // Use this to duplicate shared funtions for similar
  spec: function(target) {
    return {
      data: [],
      list: myObject.config.lists[target].guid,

      get: function() {
        myObject.d.get(a, b);
      },
      update: "",
      delete: ""
    };
  },

  // some how return `myObject.spec.get()`, allowing me to use myObject.d.prop1.get()
  prop1: myObject.spec.apply(this, "prop1"),
  prop2: myObject.spec.apply(this, "prop2")
};
Batman
  • 5,563
  • 18
  • 79
  • 155
  • 2
    Please reduce this to a minimal complete example. You reference things not defined in the example provided, which itself is missing a closing brace and rather lengthy. You also are using a keyword (get) as an object property. While that's legal in JavaScript, I'd think twice about doing so. – Jared Smith Aug 27 '18 at 19:10
  • @JaredSmith cleaned it up, hopefully that helps – Batman Aug 27 '18 at 19:17
  • If you are calling `.get()` on the object, just use `this.data` and `this.list`… – Bergi Aug 27 '18 at 19:17
  • 2
    Why not just explicitly pass the `target` property name as a parameter to `spec()`? – Bergi Aug 27 '18 at 19:18
  • Agree with @Bergi, while I think this whole idea seems a little convoluted, that's the most logical way with minimal changes to your existing structure. – Jared Smith Aug 27 '18 at 19:23
  • @JaredSmith interested in hearing if there's a better way if this seems too complex / convoluted. The reason I'm trying this approach is there's going to be a lot more methods like `get, update, delete, etc etc` so I'm trying to find a way to write it once. – Batman Aug 27 '18 at 19:30
  • @Bergi yea passing the target like this `prop1: myObject.spec("prop1")` would be fine actually. I'm having trouble figuring out how to do that tho. I'm getting an error `cannot read spec of undefined` when I try it in the console. – Batman Aug 27 '18 at 19:32
  • @Batman sounds like what you want is a [`Proxy`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). You can then trap calls to the normal operations rather than using keywords as methods. If compatibility is an issue your stuck doing it the long way. – Jared Smith Aug 27 '18 at 19:32
  • @Batman Yeah, you [cannot put that `spec` function inside the same object literal](https://stackoverflow.com/q/4616202/1048572) – Bergi Aug 28 '18 at 07:57
  • Well, i dont know how it works in javascript, but in PHP you can extend another class. The child class will have all methods and property's from it's parent which then can be overwritten (`class MyObject extends BaseObject {}`). Maybe you can google on something simular? Just an idea. – Ramon Bakker Aug 28 '18 at 15:57
  • Have a look at this thread: https://stackoverflow.com/questions/15192722/javascript-extending-class – Ramon Bakker Aug 28 '18 at 16:00

1 Answers1

0

So far the only way I was able to get it working was by setting prop1 and prop2 outside of the initial deceleration like this and explicitly declaring the target like @Bergi suggested:

var myObject = myObject || {};
myObject = {
  d: {
    get: function(list, id) {
      // do stuff
    }
  },

  // Use this to duplicate shared funtions for similar
  spec: function(target) {
    return {
      data: [],
      list: target,

      get: function() {
        myObject.d.get(a, b);
      },
      update: "",
      delete: ""
    };
  }

};

// some how return `myObject.spec.get()`, allowing me to use myObject.d.prop1.get()
myObject.prop1 = myObject.spec("prop1");
myObject.prop2 = myObject.spec("prop2");
Batman
  • 5,563
  • 18
  • 79
  • 155