JavaScript函数参数:位置->映射转换

8

我希望您能提供一个纯JavaScript的解决方案。

假设我有一个带有以下标题的函数:

generateEmail(firstName, lastname, provider)

我需要以这种方式运行它:
generateEmail("John","Smith","gmail.com");

我希望你能够使用参数映射而不是位置参数来调用它,即:
generateEmail({
  "firstName":"John",
  "lastname": "Smith",
  "provider": "gmail.com"
});

我正在寻找一个JavaScript已经写好的解决方案来处理这个问题,因为我有无限数量的函数,比如上面的generateEmail函数。是否存在这样的库?
我看到https://github.com/kilianc/node-introspect,它处理函数内省(返回函数的抽象参数信息)。但第二部分缺失 - 将映射调用映射为位置调用。
请告诉我是否存在这样的东西。
编辑:如果我没有表述清楚:我不想修改原始的位置参数函数。我从外部提供程序获取这些函数,并且可能会更新他们的代码。我更喜欢拥有一个包装器,可以在原始函数下调用,同时在外部提供一个映射参数API。

你可以检查 firstName 是否为一个对象,然后使用合适的参数再次调用 generateEmail 方法。 - Gaurang Tandon
1
@GaurangTandon 这完全不是我需要的。我需要一个通用的包装函数来处理我已经编写的内容。我可以自己编写它,但首先我想检查是否已经存在这样的东西。 - ducin
我认为使用这个 https://dev59.com/jnNA5IYBdhLWcg3wjOre 和 .apply 的组合是可能的。 - Evan Knowles
@EvanKnowles 我知道这个链接,也知道要使用.apply;主要是我知道如何编写这样的东西,但我不喜欢重复造轮子 :) 我更喜欢使用现有的解决方案。 - ducin
3个回答

3
假设您可以访问来自node-introspectintrospect(它接受一个函数并返回一个有序的参数名称列表),那么您可以简单地执行以下操作:
function objArgsify(fn) {
    var argNames = introspect(fn);
    return function(obj) {
        return fn.apply(this,
                        argNames.map(function(a) { return obj[a]; });
    }
}

用以下方式调用:

var generateEmailWithObjArgs = objArgsify(generateEmail);
generateEmailWithObjArgs({
  "firstName":"John",
  "lastname": "Smith",
  "provider": "gmail.com"
});

该函数接受一个函数作为参数,读取其参数名称,并返回一个包装函数,它接受一个对象并使用位置参数名称以正确的顺序从对象参数中提取属性。

该函数将调用时的对象参数用作映射,将数组 ["firstName", "lastname", "provider"] 转换为数组 ["John", "Smith", "gmail.com"]。 然后使用 apply 使用该数组来调用位置参数函数。


比我的解决方案整洁多了。 - Evan Knowles
我希望有一个库可以处理这个问题,我只是不想重复造轮子。无论如何,您的解决方案符合我的需求;我更多地考虑了以下内容:var argMapify = function(fn, argValues, context) { var argDefs = introspect(fn); return fn.apply(context, argDefs.map(function(arg) { return argValues[arg]; })); }并调用 argMapify(fn, {...}),因为你从外部供应商获取函数并即时调用该函数。 - ducin
1
使用 node-introspect 时要小心,因为它将函数解析为字符串。任何超出其正则表达式范围的内容(在未来,我们有ES6单参数箭头函数和可选括号)都将无法解析。简而言之,如果您考虑在实际应用中使用它,请小心。 - davidjb

2

不使用任何外部库,

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
  var fnStr = func.toString().replace(STRIP_COMMENTS, '');
  var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
  if(result === null)
     result = [];
  return result;
}

function call(method, object) {
    var params = getParamNames(method);
    var arrParams = [];
    for (var i = 0; i < params.length; i++) {
        arrParams.push(object[params[i]]);
    }
    return method.apply(arrParams);
}

只需使用 call(generateEmail, generateEmailObject) 进行调用。


0

类似于

   var orig_generateEmail = generateEmail;
   var generateEmail = function (map) {
              orig_generateEmail(map.firstName, map.lastname, map.provider);
   };

但这显然会导致一个静态“映射”列表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接