检查一个函数是否需要数组或单值输入

3
我正在尝试编写一个函数,该函数接受一个数组和另一个函数作为输入。我所知道的关于提供的函数仅限于以下两种情况之一:
  1. 接受一个数字参数并返回一个新的数字
  2. 接受一个数字数组并返回一个新的数字数组
在我的函数中,我想检查它是第一种情况还是第二种情况,以确定是否要使用 Array.prototype.map() 调用提供的函数。
因此,有了这两个函数......
var unknownFunction = function( unknownInput ) {
  //Does stuff with input

  //returns number or array of numbers...
  return someValueOrValues
}

并且

var mainFunction = function( anArray, preFunction ){

  // SOME CODE TO CHECK IF ARG NEEDS TO BE NUMBER OR ARRAY
  // ...
  // ...

    **ANSWER WOULD FIT HERE**


  if( argIsNumber === true ){
    // function takes NUMBER
    anArray = anArray.map( preFunction )
  }else{
    // function takes ARRAY
    anArray = preFunction(anArray)
  }

  // DO STUFF WITH ARRAY AFTER USER FUNCTION HAS MADE IT'S MODIFICATIONS
  // ...
  // ...
  // ...

  return anArray;
}

有没有办法深入了解第一个函数,以便找出最佳的调用方法?

2
你可以将它放在 try/catch 块中。当尝试访问一个数字时,如果它实际上是一个数组,就会触发错误... - durbnpoisn
4
这是不可能的。你无法在运行函数之前(一般情况下)确定一个函数是否接受数组或数字,即使运行了函数,也不能确定。这是“停机问题”的一个子类,它没有解决方案。 - user229044
@meagar是正确的,但你可以使用Function.prototype.toString,在大多数浏览器中返回函数源代码+一些关于参数名称的约定,例如如果第一个参数被命名为array-不是完美的专业术语,但可能有效。 - csharpfolk
1
@meagar 考虑以下代码 function unknownFunction(unknownInput) { if (Math.random() > 0.5) { treat unknownInput as a number } else { treat unknownInput as an array } }。每次调用该函数时,它都会改变自己的行为!这比停机问题还要糟糕,因为即使是相同的输入,其行为也会发生变化! - Raymond Chen
@RaymondChen,您能否通过示例函数更详细地解释一下您的评论?我不理解它的相关性。我的unknownFunction在处理其输入的方式上并没有变化,但是我的mainFunction应该能够处理返回单个值和数组的unkFuncAunkFuncB - Steve Ladavich
显示剩余3条评论
3个回答

2
由于JavaScript是一种动态类型语言,当某个人使用某个参数调用函数时,函数的输入参数就有了类型。
一种优雅且可行的方法是向整个给定的函数添加一个属性来提示输入参数的类型:
var func = function() {};
func.type = "number"; // a function decorator

var mainFunction = function(anArray, inputFunc) {
    if(typeof inputFunc != "function") {
         throw Error("Please supply a function as 'inputFunc'!");
    } 

    switch(inputFunc.type) {
        case "number":
           return anArray.map(preFunction);

        case "array": 
           return preFunction(anArray);

        default:
           throw Error("Type not supported");
    }
};

mainFunction([1,2,3], func);

当你使用动态类型语言时,你需要考虑使用约定优于配置和/或鸭子类型编码。强类型语言提供的类型安全性被良好的文档替代。
例如:
在第二个参数中提供一个带有“类型”属性的函数,以告诉mainFunction断言函数的预期类型。

1
很想知道为什么我被踩了,并且知道我的方法是否有问题。 - Matías Fidemraizer
Matias,不幸的是@kevbot(在另一个答案中)的观察是准确的 - 我没有访问函数来决定是否添加了类型属性。尽管如此,我认为这是一个相当巧妙的解决方案,如果try/catch解决方案开始出现问题,我可能会尝试找到一种使这种方法可行的方法。谢谢! - Steve Ladavich
@SteveLadavich,就像我在评论中对另一个回答者所说的那样,您不需要访问函数来向函数对象添加类型属性。只是定义这些函数的人应该添加整个属性。在AngularJS中,这种模式用于定义显式注入controller.$inject = ["$scope"],现在与装饰器一起成为常见模式。 - Matías Fidemraizer
@SteveLadavich 由你决定是否采用try-catch路线。顺便说一下,正如我之前所说的,这是一种反模式,也是解决问题最简单但最糟糕的方法... - Matías Fidemraizer
@SteveLadavich 顺便说一句,如果你甚至没有访问函数源代码的权限,在你的问题中没有提到这个细节,那么应该在那里添加。对于那些可以访问整个源代码库的人来说,我的答案是有效的,而且由于StackOverflow的答案不仅仅是为了OP(你),所以留下我的答案供未来的访问者(甚至是你,如果你能接受这种方法)也没有任何问题! :) - Matías Fidemraizer

1

我会使用try-catch方法,但测试实际函数,如果一个失败则尝试下一个。

假设这些是作为未知函数传递的函数。它们只通过将1添加到数字来修改数字。

function onlyTakesNumber(num) {
    return num + 1;
}

function onlyTakesArray(arr) {
    return arr.map(num => num + 1);
}

现在,这是你的主函数。在try内部添加额外的映射是为了测试确保如果将数组传递给onlyTakesNumber函数,则不会返回字符串。额外的测试映射将再次显示代码是否需要跳转到catch块中。
var mainFunction = function (anArray, preFunction) {

    try {
        // the map on the end checks to make sure you did not get a string back
        anArray = preFunction(anArray).map(test => test);
    }
    catch (e) {
        anArray = anArray.map(preFunction);
    }

    // Do whatever else with anArray

    return anArray;
};


console.log(mainFunction([1, 2, 3], onlyTakesArray)); // [2, 3, 4]
console.log(mainFunction([7, 8, 9], onlyTakesNumber)); // [8, 9, 10]

这里有一个JSFiddle,你可以在上面测试


可怕的解决方案。这被称为反模式!! - Matías Fidemraizer
你不需要访问那些函数就能够向函数对象中添加属性。 - Matías Fidemraizer
正确,但他不知道要向属性添加什么值,因为他无法阅读函数以了解它应该接受什么类型的参数,是数字还是数组。 - KevBot
额...当我建议OP添加一个type属性时,我并没有考虑实时评估函数。您将在定义函数的同一文件中添加type属性,因为编写该函数的人已经知道预期输入参数类型是什么... - Matías Fidemraizer
是的,我同意,我也不想让这变成你的问题和我的问题。但我认为我们有一个误解的地方在于,从我所读到的和对问题的理解上来看,OP没有访问未知函数的源代码。例如,它可能是第三方库或从库中导入的内容等。当然,如果他可以访问这些函数的源代码,我同意你的解决方案会更好地解决这个问题,但我的答案是基于OP无法访问源代码的假设,正如问题中所述。 - KevBot
显示剩余3条评论

-1
最简短的答案是:“你不能”。

1
最短的注释是“为什么?” - Okan Kocyigit
你不行! 除非你硬编码返回它们,否则没有外部函数可以访问另一个函数的参数。 - Bekim Bacaj
@ocanal,每个刚接触JavaScript的新手都知道——询问是否有某种黑客技巧是不被允许的——但答案永远是:不行,你不能这样做——因为这是一个安全问题。 - Bekim Bacaj

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