根据输入参数动态生成 JavaScript 中的函数

Dynamically generate a function in JavaScript depending on input parameters

我有一个成本函数,它应该根据用户和对象的参数输出成本。 作为一个简单但不现实的例子,让我们考虑:

// 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 转换为 [=14= 中的直接浮动元素].

我的问题是我不知道如何实现功能costFunctionGenerator

您要查找的模式名称称为柯里化函数。

在 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 和 returns 新 lambda 的地方,它只需要传递对象:

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.

我创建了一个 benchmark 来测试柯里化版本是否提供任何性能优势并且确实执行得更快。