Deeply nested object data can get unreadable pretty quick. It also can be problematic if accessing data with dot or bracket notation in multiple places in your code and the shape of the data changes. Currently bracket notation accepts strings but there would be a lot of useful things you could do if it accepted arrays. Some simple examples might be:
In scenarios where you have nested JSON you could more easily dynamically construct the path for accessing your data. Also, it would allow you to store deeply nested paths in variables so that you didn’t repeat the path constantly and had a single source of truth. So instead of having obj.users[0].userInfo.name.firstName throughout your code you could have the following:
const firstName = (index) => `users.${index}.userInfo.name.firstName`.split(".");
let name = obj[firstName(0)];
obj[firstName(0)] = "Jane";
Thanks for taking a look! Any opinions/feedback is appreciated!
The main issue here is that obj[['x', 'y']] is already valid Javascript. Anything that goes in the brackets gets stringified before a lookup, so obj[['x', 'y']] would cause the key 'x,y' to be accessed from obj.
Totally! Yeah, I should have thought of that . You currently just get a string key of that array. I like the idea of a helper function. How would you set values using the array?
That all makes sense! A get and set property function seems like a solid approach. I do wonder though if there would be some option that mimics bracket notation just for simplicity's sake.
Honestly, as we go back and forth I'm starting to wonder if there is a way to achieve something similar with proxy objects?
Even with proxies, a key will be stringified before it's passed to the handler function - which is ok if none of your keys have commas, and you want to just .split(',') the key on commas.
I will also note that utility libraries such as lodash will provide these helper functions for you. Lodash provides them as _.get() and _.set(). For example:
With the only difference that the @[] operator could not only be used to enable overloading access on the object, but also to accept any object type as a key (in contrary to the normal [] accessor that directly calls .toString on the object it receives, so that it is always a string).
The advantage would be that any given object would stay intact inside @[] custom get / set handlers, whereas in the proxy solution, objects like ({a: 1, b:2}) would have been already stringified to "[object Object]", and so being unusable inside the proxy get / set handlers.
Also, we would explicitly indicate that we want to treat the object as is (and not use its stringified value), so it would be more understandable than using proxies under the hood.
Here is an example to show how it could work for this use case:
// Custom getter function
const getter = function (path) {
let value = this;
path.forEach(key => { value = value?.[key]; });
return value;
}
// Custom setter function
const setter = function (path, value) {
let target = this;
let lastKey = path.at(-1);
path.slice(0, -1).forEach(key => {
if (typeof target[key] !== "object") target[key] = {};
target = target[key];
});
target[lastKey] = value;
}
// The object, with overloaded data accessor operator
const obj = {
// Data accessor overloads
[Symbol.getDataValue]: getter,
[Symbol.setDataValue]: setter,
// Data
name: {
fName: "John",
lName: "Smith",
},
// Just to test
"name,fName": "test",
}
// We can now use the `@[]` operator to get / set values using an array
const path = ["name", "fName"];
obj@[path] = "Jane";
obj@[path] += "y"; // value becomes "Janey"
// Normal `[]` accessor still works as usual
obj[path] === "test"
That's a nice connection that I didn't even think about @Clemdz - that would be another good solution if we wanted to enable this functionality on specific objects without being too tricky. It's interesting the different ideas that come out of that overloadable data accessor proposal.
Wow, wasn't getting notifications and didn't expect to see so many responses. I am aware of lodash's get and set options. I also really agree that the spread syntax is really intuitive. So many interesting and good points here!