Murky
Murky

Reputation: 13

Accessing array inside of object from inside the same object

I've done similar things before but I can't get this to work.

I run this and get "Cannot read property '0' or undefined..."

(The randomResult() function returns a random element from a passed array and works ok elsewhere.)

var objectOfArrays = {
  array1: ["apple","orange","pear","mango"],
  array2: [
    "I want no fruit!",
    "I will have one " + randomResult(this.array1) + "."
  ]
}

console.log(randomResult(objectOfArrays.array2));

Upvotes: 0

Views: 75

Answers (2)

ZER0
ZER0

Reputation: 25322

The object is not defined yet, you can't use this inside an object declaration.

To be clear, something like that:

const obj = {
  a: 1,
  b: this.a,
  c: obj.a
}

Won't work, both b and c cannot access to the object that is currently declared.

However, if you delay the access, then it will works:

const objectOfArrays = {
  array1: ["apple","orange","pear","mango"],
  get array2() {
    return [
      "I want no fruit!",
      "I will have one " + randomResult(this.array1) + "."
    ]
  }
}

Defining a getter the code will be executed only when you're trying to access to objectOfArrays.array2. Keep in mind two things, however: first, it will be readonly: if you want to set also the prop array2 you have to create a setter too. Second, and more important, in this way, every time you access to array2 the getter is executed, therefore a new array is returned – with a new random result from array1. If you want to return the same, you have to cache the result somewhere:

const objectOfArrays = {
  array1: ["apple","orange","pear","mango"],
  _array2: null, // this could be actually omitted, see `Symbol` example
  get array2() {
    return this._array2 || (this._array2 = [
      "I want no fruit!",
      "I will have one " + randomResult(this.array1) + "."
    ])
  }
}

(You could use Symbol for make the property more private, but it's better not over complicate things now)

Using Symbol

Since it was asked in the comment, even if it's outside the scope of the answer.

Caching the property to _array2 is good enough in most of the cases; however the property is easily accessible directly:

console.log(objectOfArrays._array2) // null

And can be tampered easily:

objectOfArrays._array2 = [1, 2];

Changing the behavior of the getter in array2.

A Symbol could be used to make _array2 more private. Assuming we are in a module:

const _array2 = Symbol("array2"); // the string is just for debug

export default objectOfArrays = {
  array1: ["apple","orange","pear","mango"],
  get array2() {
    return this[_array2] || (this[_array2] = [
      "I want no fruit!",
      "I will have one " + randomResult(this.array1) + "."
    ])
  }
}

In this way, outside the module there is no a direct way to refer the "private" _array2 property, since the Symbol is needed – and we do not export that. It won't also appear in iteration (for example, with Object.keys(objectOfArrays)). Of course there is still a way to access to it, using getOwnPropertySymbol, but that means usually a more deliberate code than an accident one – e.g. iterate the keys of an object.

I mentioned module, but this is also applying if we're using a block scope:

 // create a block
 {
   // const is block scoped, therefore is not accessible outside
   const _array2 = Symbol("array2");

   // `var` is not block scoped, so it will be accessible outside
   // also `global.objectOfArrays` would be valid, where `global`
   // is a reference to the global object (there is a spec to have
   // it by default but is not implemented yet.
   var objectOfArrays = ... // same code
 }

Or in a closure:

 (function(exports) {
   const _array2 = Symbol("array2");

   exports.objectOfArrays = ... // same code
 }(this)); // or `window` or whatever is the export object / global one.

Upvotes: 2

Slai
Slai

Reputation: 22866

Alternative can be temporary variable:

var temp, objectOfArrays = {
  array1: temp = ["apple","orange","pear","mango"],
  array2: [
    "I want no fruit!",
    "I will have one " + temp + "."
  ]
}

console.log( objectOfArrays );

or separate statements:

var objectOfArrays = { array1: temp = ["apple","orange","pear","mango"] };

objectOfArrays.array2 = [ "I want no fruit!",
    "I will have one " + objectOfArrays.array1 + "." ];

console.log( objectOfArrays );

Upvotes: 0

Related Questions