Чистые функции в javascript

#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. Сначала я написал фильтр, но он фильтрует только имя — не знаю почему, но я ожидал больше атрибутов, чем имя. В любом случае, добавлены оба