#javascript #functional-programming
#javascript #функциональное программирование
Вопрос:
Я понимаю, что функции должны быть чистыми, чтобы избежать побочных эффектов. Например, следующая функция:
//Approach 1
buildValidationErrors(state){
let validationErrors = [];
if(state.name === null)
{
validationErrors.push("Name");
}
if(state.email === null)
{
validationErrors.push("Email");
}
if(state.mobile === null)
{
validationErrors.push("mobile");
}
return validationErrors;
}
//Approach 2
_buildError(state,itemName,validationErrors){
if(state[itemName] === null){
validationErrors.push(itemName);
}
}
buildValidationErrors1(state){
let validationErrors = [];
_buildError(state,"Name",validationErrors );
_buildError(state,"Email",validationErrors);
_buildError(state,"mobile",validationErrors);
return validationErrors;
}
В «Подходе 1» у вас есть функция long, которая создает массив. В «Подходе 2» я извлекаю повторно используемую логику в «_buildError», чтобы избежать дублирования логики.
Однако в подходе 2 передается параметр ValidationErrors, и он также обновляется, в результате чего функция становится «нечистой», насколько я понимаю.
С этой точки зрения, может ли функция быть чистой и компактной?
Ответ №1:
Вы можете избежать передачи массива ошибок, объединив результаты вне _buildError()
функции:
_buildError(state,itemName){
return state[itemName] === null ? itemName : null;
}
buildValidationErrors1(state){
let validationErrors = [];
validationErrors.push(
_buildError(state,"Name"),
_buildError(state,"Email"),
_buildError(state,"mobile")
).filter((a)=> a !== null);
return validationErrors;
}
Однако это на самом деле не меняет чистоты функции. В вашем 2-м примере функция зависит и изменяет только свои параметры, поэтому она достаточно «чистая» для автоматических тестов и других практических целей.
Ответ №2:
Я бы рассмотрел
_buildError(state,itemName){
return state[itemName] === null ? itemName : null;
}
// reduce if you need more than one thing in the validation array
let validationErrors = ["Name","Email","mobile"]
.reduce((acc,item) => {
if (_buildError(state,item)) acc.push({item,something:state[item].something}); return acc },
[] );
// filter if you just need the item name
let validationErrors = ["Name","Email","mobile"]
.filter(item => _buildError(state,item));
Комментарии:
1. Похоже, что вы должны использовать
filter
, а неreduce
push
.2. Сначала я написал фильтр, но он фильтрует только имя — не знаю почему, но я ожидал больше атрибутов, чем имя. В любом случае, добавлены оба