Reputation: 13
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
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
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