JavaScript. Доступ к свойству через скобочную запись при передачи названия свойств переменной
В JS есть замечательная возможность получить значение свойства объекта как через точечную нотацию (obj.prop) так и через скобочную (obj['prop'])
Условно у нас имеется следующий объект:
let object = {
name: 'UserName',
userProps: {
age: 30,
details: {
city: 'London'
}
}
};
Так же у нас есть метод, который принимает название свойства и новое значение и присваивает новое значение объекту:
const onChange = (propName, value) => {
object[propName] = value;
};
Все понятно для случая когда я передаю первым аргументом name, но что нужно передавать и как, чтобы заменить значение свойства city или age? Заранее благодарю.
const object = {
name: 'UserName',
userProps: {
age: 30,
details: {
city: 'London'
}
}
};
const onChange = (propName, value) => {
object[propName] = value;
};
onChange('name', 'newName');
console.log(object);
Ответы (3 шт):
const obj = {
name: 'UserName',
userProps: {
age: 30,
details: {
city: 'London'
}
}
};
const onChange = (o, path, value) => {
const props = path.split('.');
for (let i = 0; i < props.length - 1; i++) {
o = o[props[i]];
}
o[props[props.length - 1]] = value;
};
onChange(obj, 'name', 'newName');
onChange(obj, 'userProps.details.city', 'New York');
console.log(obj);
Проверки - самостоятельно.
Или менять функцию onChange или так:
onChange('userProps',{
age: 50,
details: {
city: 'Moscow'}
});
const object = {
name: 'UserName',
userProps: {
age: 30,
details: {
city: 'London',
},
},
};
const onChange = (...args) => {
const [finalPropName, value] = args.splice(-2, 2);
args.reduce((obj, propName) => obj[propName])[finalPropName] = value;
};
onChange(object, 'userProps', 'age', 32);
onChange(object, 'userProps', 'details', 'city', 'Manchester');
console.log(object);
В первой строке функции извлекаем два последних аргумента (удаляя их из args), во второй - получаем последнее по вложенности объектное свойство, и присваиваем уже его свойству (имя которого извлекли из предпоследнего аргумента) новое значение (извлекли из последнего аргумента).
Как тут выполняется reduce: это по сути своей цикл по args, на первой итерации которого obj принимает значение первого элемента (в данном случае, object), а далее значение obj последовательно заменяется на obj[propName], где propName содержит значение текущего элемента args (элементы перебираются в порядке их следования, конечно же).
Если хочется передавать путь к свойству строкой с разделителем-точкой, это можно так:
onChange(object, ...'userProps.details.city'.split('.'), 'Liverpool');
, но я не рекомендую так делать, т.к. вообще имена свойств могут содержать символ . (и тогда сплит по нему не сможет корректно разделить путь на фрагменты). Вместо этого, фрагменты пути можно сразу собирать в массив типа ['foo', 'bar.baz', 'qux'], и деструктурировать его в аргументы.
Еще хочется сразу предостеречь от добавления проверок: в данной функции не надо их добавлять, потому что стандартным поведением JS при обращении к несуществующему свойству / несовместимости типов является бросание ошибки, и такое поведение ожидаемо - ему лучше соответствовать. Вызывающий код формирует аргументы, а значит и обработка ошибок (из-за них) является ответственностью именно вызывающей стороны:
try {
onChange(/* .... */);
} catch (err) {
/* .... */
}