Javascript: получить доступ к члену объекта (ассоциативного массива) на любой глубине при условии, что промежуточные члены могут отсутствовать
Допустим, необходимо получить доступ к свойству:
data.a.b.c.d.e.f
Или получить undefined
, если такое свойство отсутствует (в том числе по причине отсутствия промежуточных членов объекта data
, например при отсутствии a
, b
, c
и т.д.).
Если использовать предусмотренную для этого конструкцию ?.
, то получаются такие вещи:
data?.a?.b?.c?.d?.e?.f
Вопрос:
Можно ли запись сделать более короткой и понятной, чем у каждого члена ставить ?.
?
Ответы (2 шт):
Как возможный вариант, могу предложить простую реализацию метода get
с помощью try..catch
:
const get = (obj, propsPath) => {
try {
const paths = propsPath.split('.');
let result = obj;
for (const path of paths) {
result = result[path];
}
return result;
} catch (e) {
return undefined;
}
}
const data = {
a: {
b: {
c: {
d: {
e: {
f: 45
}
}
}
}
}
}
const results = [
get(data, ''),
get(data, 'a'),
get(data, 'a.b'),
get(data, 'a.b.c'),
get(data, 'a.b.c.d'),
get(data, 'a.b.c.d.e'),
get(data, 'a.b.c.d.e.f'),
get(data, 'a.b.c.d.e.f.g'),
get(data, 'a.b.c.d.e.f.g.h'),
get(data, 'a.b.c.d.e.f.g.h.i'),
].map(result => result === undefined ? result : JSON.parse(JSON.stringify(result)));
console.log(results);
P.S. Такая простая реализцаия не будет отличать существование поля с значением undefined
и отсутствием самого поля вообще, но это легко исправить
Эксперимент с использованием Proxy
. К сожалению, я не сумел возвращать undefined
, вместо него undefinedProxy
, что снижает уровень красивости решения. Но изменить поведение .
можно:
const isDict = v => v !== undefined && v !== null && v.constructor === Object;
const undefinedProxy = new Proxy({}, {
get(target, prop, receiver) {
return undefinedProxy;
}
});
const makeProxy = data => new Proxy(data, {
get(target, prop, receiver) {
if (prop in target) {
const value = target[prop];
return isDict(value) ? makeProxy(value) : value;
}
return undefinedProxy;
}
});
const data = {a: {b: {z: 42}}};
const p = makeProxy(data);
console.log('data', data);
console.log('p', p);
console.log('p.a', p.a);
console.log('p.a.b', p.a.b);
console.log('p.a.b.c', p.a.b.c);
console.log('p.a.b.c.d', p.a.b.c.d);
console.log('p.a.b.c.d.e', p.a.b.c.d.e);
console.log('p.a.b.c.d.e.f', p.a.b.c.d.e.f);
console.log('p.a.b.c.d.e.f === undefinedProxy', p.a.b.c.d.e.f === undefinedProxy);
console.log('p.a.b.z', p.a.b.z);