Динамически генерировать функцию в JavaScript в зависимости от входных параметров - PullRequest
1 голос
/ 20 мая 2019

У меня есть функция стоимости, которая должна выводить стоимость в зависимости от параметров пользователя и объекта.В качестве простого, но нереалистичного примера, давайте рассмотрим:

// example of input user
let user1 = {
  access: [true, false], 
  utility: [2, 5]
};
// example of input object
let object1 = {type: 0, cost: 15};

// static vertions of the cost function
const costFunction = (user, object) => {
  switch (object.type){
    case 0:
      if(user.access[0]){
        return object.cost * user.utility[0];
      }else{
        return Infinity;
      };
    case 1:
      if(user.access[1]){
        return object.cost * user.utility[1];
      }else{
        return Infinity;
      };
  };
};

costFunction(user1, object1)    // sould return 2*15 = 30

Однако в алгоритмах мне приходится вызывать эту функцию очень большое количество раз с одним и тем же пользователем, но с разными объектами.Итак, я хотел бы иметь возможность обрабатывать параметры пользователя только один раз и динамически генерировать адаптированную пользователем функцию стоимости следующим образом:

// dynamically generated a user-adapted const function
const costFunctionGenerator = (user) => {
    ... some code ... 
    const costFunction = (object) => {
        ... some code ...
    };
    return costFunction;
};

const user1CostFunction = costFunctionGenerator(user1)

Так, чтобы user1CostFunction было равно

const user1CostFunction  = (object) => {
   switch (object.type){
      case 0:
         return object.cost * 2;
      case 1:
         return Infinity;
   }
}

Что случилось, так это то, что мы удалили условия if, которые исходят из параметров пользователя user1.access, а также мы преобразовали ссылки из user1.utility в прямые элементы с плавающей точкой в ​​user1CostFunction.

Моя проблема в том, что я понятия не имею, как реализовать функцию costFunctionGenerator.

1 Ответ

1 голос
/ 20 мая 2019

Название шаблона, который вы ищете, называется каррированием функции.

В pre-es6 создание Javascript функций карри было немного неуклюжим, но с появлением функций со стрелками синтаксис стал намного приятнее. По сути, единственное, что вам нужно сделать, это изменить свою подпись на:

const costFunctionCurried = (user) => (object) => {
  switch (object.type){
    case 0:
      if(user.access[0]){
        return object.cost * user.utility[0];
      }else{
        return Infinity;
      };
    case 1:
      if(user.access[1]){
        return object.cost * user.utility[1];
      }else{
        return Infinity;
      };
  };
};

Но как это работает? Когда вы звоните costFunctionCurried в первый раз, он исправляет все места, где вызывается переменная user и возвращает новую лямбду, которая ожидает передачи только объекта:

costFunctionCurried(user1)(object1) //you can call it inline

//or you can assign your function to a variable for reuse
const fixedUserCostFunction = costFunctionCurried(user1) 

fixedUserCostFunction(object1)
fixedUserCostFunction(object2) //etc.

Я создал бенчмарк , чтобы проверить, дает ли карри версия какую-либо выгоду производительности и действительно ли она работает быстрее.

...