Reputation: 117
To make things more clear, here's an example. I tried to strip everything down to the bone and only keep the relevant details. Here's a dummy class Person
with some properties and subproperties:
class Person {
height = 100;
hat = {size: 4};
}
Now, I have some other class whose purpose is to modify some (sub)*property of Person
:
class PersonModifier {
constructor(propertyPath, value) {
this.propertyPath = propertyPath; // this is the part I'm a bit lost on
this.value = value; // a numeric value just to demonstrate how this class would work
}
actUpon(person) { // modifies a quantitative attribute of Person by a given amount
person.(this.propertyPath) += value;
}
}
I'm aware the sole line of code inside the actUpon
method doesn't work syntactically, I hope I got the point across as to what I'm trying to do. I guess it's similar to Person.prototype.whatever
but I'd like to use it for attributes and not for methods.
Here's an example of instance of the above class, whose purpose is to decrease one's hat size by 2:
let hatShrinker = new PersonModifier(.hat.size, -2);
Again, that obviously doesn't work syntactically, so here's my question:
How do I store and use a property path (of arbitrary depth), such that I can access and write such properties of any object? Consider that I know what classes the object belongs to beforehand (in this example, Person
).
Note: any solution not involving strings would be preferred, as strings are not affected by some important IDE features like refactoring and suggestions based on dynamic type
Upvotes: 1
Views: 538
Reputation: 16596
I do think you're probably stuck with strings of some sort. In this example, I use an array of strings to dive down the object path and mutate the final key of the final object.
class PersonModifier {
constructor(propertyPath, value) {
this.propertyPath = propertyPath;
this.value = value;
}
actUpon(person) {
const path = [...this.propertyPath];
const prop = path.pop();
const obj = path.reduce((acc, el) => {
return acc[el];
}, person);
obj[prop] += this.value;
}
}
const hatShrinker = new PersonModifier(["hat", "size"], -2);
const person = {
hat: {
size: 4
}
};
hatShrinker.actUpon(person);
console.log(person);
Upvotes: 2