0
function fnDrawPrism(length, width, height){
        //If any of these parameters are undefined, throw an error that lists the missing parameters.
        return length*width*height;
}

在 JavaScript 中,我试图获取函数中所有参数的名称undefined。如果此函数中的任何参数未定义,那么我希望该函数抛出一个列出缺失参数名称的错误。

我找到了解决这个问题的方法,但是它需要为每个参数单独的条件语句,我想知道是否有更简洁的方法来获取未定义参数的列表:

var toReturn = "";
if((typeof length == "undefined") || (length == "undefined")){
    toReturn += "length is not defined!";
}
if((typeof width == "undefined") || (width == "undefined")){
    toReturn += "width is not defined!";
}
if((typeof height == "undefined") || (height == "undefined")){
    toReturn += "height is not defined!";
}
if(toReturn != ""){
    throw new Error(toReturn); //if any parameters are missing, then list the names of all missing parameters
}
4

6 回答 6

3

您可以将它们保存在一个对象中并遍历它的键:

function fnDrawPrism(length, width, height){
    var params = {
        length: length,
        height: height,
        width: width
    }

    for(var field in Object.keys(params))
    {
        if(params[field] === undefined)
        {/* do what you want */}
    }
    ...
}

为不想多想的人编辑

这应该在函数中完成。

于 2013-06-30T04:46:53.260 回答
2

javascript 中没有简单的方法来获取函数的第一个或第二个或第 n 个参数的名称。可以检查函数的字符串版本并将它们解析出来,但我怀疑你是否想要这样做。

您可以在数组或对象中构建自己的名称列表,然后使用该arguments对象遍历参数检查每个参数的有效性,然后使用您自己的名称数组获取第 n 个名称(如果有错误) .

例如,您可以像这样检查每个参数:

function fnDrawPrism(length, width, height){
    //If any of these parameters are undefined, throw an error that lists the missing parameters.
    var argNames = ["length", "width", "height"];
    if (arguments.length < argNames.length) {
        // throw first arg that is missing
        throw new Error(argNames[arguments.length] + " is undefined");
    }
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] === undefined) {
            throw new Error(argNames[i] + " is undefined");
        }
    }
    // now that all args are defined do the business of the function
    return length*width*height;
}

在这里工作演示:http: //jsfiddle.net/jfriend00/9PH6P/


如果您想重构代码并传递带有键/值作为参数的单个对象,那么迭代它们并从传递的对象键中获取 arg 名称要容易得多。但是,我假设您是在问一个关于带有多个参数的普通函数调用的问题,所以这就是我在上面提供的答案。

于 2013-06-30T04:48:41.250 回答
2

这是一个独立的验证函数,您可以在任何函数中使用它来检查传递的参数是否存在和使用匈牙利符号的类型正确性:

function fnDrawPrism(length, numWidth, intHeight){
    //If any of these parameters are undefined, throw an error that lists the missing parameters.
    // you can cut-and-past the declaration line to fill out 90% of the validation call:
    validate(fnDrawPrism, length, numWidth, intHeight); 

    return length * numWidth * intHeight;
}

// this is cut-and-pasted into a file somewhere, edit to add more types or stricter checking
function validate(args){
    var fn = args, actuals = [].slice.call(arguments, 1),
        hung = {int: "Number", num: "Number", str: "String", arr: "Array",
        obj: "Object", inp: "HTMLInputElement", dt: "Date", bln: "Boolean",
        rx: "RegExp", frm: "HTMLFormElement", doc: "HTMLDocument"},
        names = String(fn).split(/\s*\)\s*/)[0].split(/\s*\(\s*/)[1].split(/\s*\,\s*/),
        mx = names.length, i = 0;
    if(!fn.name)
        fn.name = String(fn).split(/\s*(/)[0].split(/\s+/)[1] || 'anon';
    for(i; i < mx; i++){
        if(actuals[i] === undefined)
            throw new TypeError("missing arg #" + i + " in " + fn.name + " - " + names[i]);
        var hint = hung[names[i].split(/[A-Z]/)[0]],
            got = toString.call(actuals[i]).split(/\W/)[2];
        if(hint && got !== hint)
            throw new TypeError("Wrong type in argument #" + i + " of " + fn.name + " - " + names[i] + ". Got: " + got + ", Expected: " + hint);
}

//try it out:
fnDrawPrism(1);       //! missing arg #1 in fnDrawPrism - numWidth
fnDrawPrism(1,4);     //! missing arg #2 in fnDrawPrism - intHeight
fnDrawPrism(1,2,3);   // ok
fnDrawPrism(1,"2",3); //! Wrong type in argument #1 of fnDrawPrism - numWidth. Got: string, Expected: number

您不能只将“参数”传递给验证器的原因是严格模式对参数对象施加了太多限制,无法可靠地使用它。Ecma6 将有一种一次性传递所有参数的方法,但是这只适用于未来的浏览器,而长手方式适用于当时、现在和永远的浏览器......

编辑:更新基于注释的验证例程,使其更加强大,将文档、输入、表单、数组、正则表达式、日期和对象添加到匈牙利符号验证例程,现在也可以跨窗口对象工作。

于 2013-06-30T05:09:12.027 回答
1

您走在正确的轨道上-这是我将其提取到辅助函数中的方法,并通过列出所有缺少的参数来使抛出的错误更具信息性:

function validateParams(names, vals) {
    var missing = [];
    for (var i=0; i<names.length; i++) {
        if (vals[i] === undefined) missing.push(names[i]);
    }
    if (missing.length > 0) throw "Missing arguments: " + missing.join(', ');
}

function fnDrawPrism(length, width, height){
    validateParams(['length', 'width', 'height'], [length, width, height]);
    return length * width * height;
}
于 2013-06-30T05:20:46.700 回答
0

在我看来,一个更通用的“缺少参数 2”类型异常就足够了 - 看到这种异常的开发人员会去检查参数 2 实际上是什么。此外,谈论“未定义”而不是“缺失”可能会更好,因为有人可能会说fnDrawPrism(undefined, 1, 2);在这种情况下第一个参数实际上并不是“缺失”。

无论如何,如果您决定在这里显示名称,这就是我想出的,.toString()在函数上使用和正则表达式来获取参数名称:

function fnDrawPrism(length, width, height){
    var msg = [],
        argNames = fnDrawPrism.toString().match(/\(([^)]*)\)/)[1].split(/\s*,\s*/);
    for (var i = 0; i < fnDrawPrism.length; i++)  // for each declared argument
      if (typeof arguments[i] === "undefined")
          msg.push(argNames[i]);
    if (msg.length > 0)
        throw new Error("fnDrawPrism missing argument(s): " + msg.join(", "));

    // ACTUAL function body goes here
}

假设您想在所有函数中进行类似的验证,您可以将其提取到单独的函数中:

function testFuncArgs(fn, args) {
    var msg = [], argNames = fn.toString().match(/\(([^)]*)\)/)[1].split(/\s*,\s*/);
    for (var i = 0; i < fn.length; i++)   // for each declared argument
      if (typeof args[i] === "undefined")
          msg.push(argNames[i]);
    if (msg.length > 0)
        throw new Error("Function "+fn.name+" missing argument(s): "+ msg.join(", "));
}

function fnDrawPrism(length, width, height){
    testFuncArgs(fnDrawPrism, arguments);

    // ACTUAL function body goes here
}

function someOtherFunction(a, b, c, d){
    testFuncArgs(someOtherFunction, arguments);

    // Actual function body here
}

请注意,当有人使用太多参数调用您的函数时,您可能希望添加额外的检查,即if (arguments.length > fnDrawPrism.length).

于 2013-06-30T05:19:59.637 回答
0

您可以使用Function.prototype.toString提取名称:

function get_args(fn) {
    return fn.toString().match(/\((.*)\)/)[1].split(", ")
}

对于您的功能:

function fnDrawPrism(length, width, height){
    return length*width*height;
}
get_args(fnDrawPrism) // [ 'length', 'width', 'height' ]
于 2013-06-30T04:51:23.587 回答