Skip to content

Instantly share code, notes, and snippets.

@ryanmorr
Last active March 29, 2024 03:11
Show Gist options
  • Save ryanmorr/c750659b2d82c372955e819774500c23 to your computer and use it in GitHub Desktop.
Save ryanmorr/c750659b2d82c372955e819774500c23 to your computer and use it in GitHub Desktop.
Get and set deeply nested object properties via paths
const has = {}.hasOwnProperty;
function getPath(root, tester, path = []) {
for (const key in root) {
if (has.call(root, key)) {
const value = root[key];
if (tester(key, value) === true) {
path.push(key);
return path;
}
if (typeof value === 'object' && value !== null) {
const copy = path.slice().concat([key]);
const result = getPath(value, tester, copy);
if (result) {
return result;
}
}
}
}
}
function setPath(root, path, value) {
let obj = root;
const copy = path.slice();
while(obj && copy.length > 0) {
const prop = copy.shift();
if (copy.length === 0) {
obj[prop]= value;
} else {
obj = obj[prop];
}
}
}
// Usage:
const obj = {
a: {
b: {
c: 10,
d: {
e: 20
}
},
f: {
g: 30,
h: 40,
i: {
j: 50
},
k: {
l: {
m: 60
}
}
},
n: {
o: 70
}
},
p: {
q: 80
}
};
// Provide a test function to get the path to the first property that satisfies a condition
const path = getPath(obj, (key, val) => val === 60); //=> ["a", "f", "k", "l", "m"]
console.log(obj.a.f.k.l.m); //=> 60
// Set a new value for the property with the given path;
setPath(obj, path, 100);
console.log(obj.a.f.k.l.m); //=> 100
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment