Какие кейсы нужно обрабатывать при работе с путями в объектах и массивах
Что проверяют
Обычно это подводка к задаче «напишите свой get(obj, path, defaultValue)» или set, как в lodash. Проверяют, видите ли вы крайние случаи до того, как они сломают код, и отличаете ли «значения нет» от «значение ложное». Следом часто просят написать set, не мутируя исходный объект.
Как отвечать
Перечислите кейсы и для каждого скажите, как обработаете:
- формат пути: строка
"a.b[0].c", строка"a.b.0.c"и массив["a", "b", 0, "c"]. Строку разбирайте в массив ключей один раз; - ключи с точкой:
{ "a.b": 1 }строковым путём не достать, поэтому путь массивом нужно поддерживать обязательно; - пустой путь: явно решите, вернуть сам объект или дефолт;
- обрыв цепочки: промежуточный
null,undefinedили примитив. ВместоTypeErrorвозвращается значение по умолчанию; - ложные значения:
0,"",falseиnullэто найденные значения, подменять их дефолтом нельзя. Поэтому??, а не||, и дефолт только когда результатundefined; - унаследованные свойства: путь
"toString"найдёт метод прототипа. Если это нежелательно, проверяйтеObject.hasOwn; - индексы массивов: отрицательные, за пределами длины, нечисловые ключи у массива;
- безопасность в
set: ключи__proto__,constructorиprototypeзапрещаются, иначе получите prototype pollution; - промежуточные узлы в
set: если следующий ключ число, создаётся массив, иначе объект; - неизменяемость: для состояния в React
setкопирует только узлы по пути и переиспользует остальные ветки. Изменение видно по ссылке, а нетронутые компоненты подReact.memoне перерисовываются.
Optional chaining a?.b?.[0] годится только для путей, известных при написании кода.
Где спотыкаются
Пишут get(obj, path) || defaultValue. Число 0 или пустая строка в данных превращаются в дефолт, и баг ловят уже в продакшене.
Оборачивают обход в try/catch. Это прячет настоящие ошибки и превращает обычный отсутствующий ключ в дорогое исключение.
Реализуют set мутацией исходного объекта. Компонент React не перерисуется, а в редьюсере без Immer это прямое нарушение правил Redux.