1

I am trying to build a js object that a property can reference another property in the same object, is this possible? this is my idea but it is not working, hope I am clear enough:

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] },
   c: { properties: docs.a.properties.concat(docs.b.properties) }
};

document.write(docs.c.properties);

console says it can´t find docs.a

Uncaught TypeError: Cannot read property 'a' of undefined.

bto.rdz
  • 6,636
  • 4
  • 35
  • 52
  • Just to start with, or should `c` be an ongoing reflection of the combination of `a` and `b`? If the former, this is a duplicate of [this question](http://stackoverflow.com/questions/4616202/self-references-in-object-literal-declarations). – T.J. Crowder Feb 20 '16 at 16:13

2 Answers2

5

You cannot do that because the object docs is not yet created. You could do something like the following:

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] }
}
docs.c = { properties: docs.a.properties.concat(docs.b.properties) };

document.write(docs.c.properties);

Alternatively, you could do something like this: (excerpt from this answer)

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] },
   init: function() {
       docs.c = { properties: docs.a.properties.concat(docs.b.properties) };
       return this;
   }
}.init();
Community
  • 1
  • 1
  • In other words, to reference an object from two different places, you need to first finish creating a reference to it. – Ruan Mendes Feb 20 '16 at 16:12
  • 1
    I know I can do this, but I dont like that pattern because this object will be used to lead documentation for a website, so it is a big object and this will end as a really confusing and complicated obejct – bto.rdz Feb 20 '16 at 16:15
  • @bto.rdz I edited the answer, providing another way of doing this. Gives essentially the same result. – Martin Aparicio Pons Feb 20 '16 at 16:21
  • @MartinAparicioPons Thanks I am evaluating all options :) – bto.rdz Feb 20 '16 at 16:21
2

Assuming you want c to always mirror a and b, not just at the outset, you can define it with a getter function:

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] },
   get c() {
       return { properties: docs.a.properties.concat(docs.b.properties) };
   }
};
console.log(docs.c.properties.join(", ")); // "1, 2, 3"

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] },
   get c() { return { properties: docs.a.properties.concat(docs.b.properties) }; }
};
console.log("a: " + JSON.stringify(docs.a));
console.log("b: " + JSON.stringify(docs.b));
console.log("c: " + JSON.stringify(docs.c));

Note that every access to c will create a new object and a new concatenated array, so it's not particularly efficient. But if you want it to be dynamic...

Or since it's just c.properties that you really need to have a getter:

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] },
   c: { get properties() {
           return docs.a.properties.concat(docs.b.properties);
        }
      }
};
console.log(docs.c.properties.join(", ")); // "1, 2, 3"

var docs = {
   a: { properties: [1, 2] },
   b: { properties: [3] },
   c: { get properties() {
           return docs.a.properties.concat(docs.b.properties);
        }
      }
};
console.log("a: " + JSON.stringify(docs.a));
console.log("b: " + JSON.stringify(docs.b));
console.log("c: " + JSON.stringify(docs.c));

There, just c.properties is recreated each time, not c itself.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • That's tricky awesome, I was trying to think of something along those lines, but something about recreating that array every time... but I guess it can easily be cached – Ruan Mendes Feb 20 '16 at 16:13
  • @JuanMendes: Yeah, it's definitely not very efficient recreating it every time. – T.J. Crowder Feb 20 '16 at 16:16
  • If that's what OP wants, it should be noted that it'll construct a new object on every access to `c`, so object comparisons from that property will never result in `true`. *(referring to the first example)* –  Feb 20 '16 at 16:16