如何在JavaScript函数中获取缺少参数的名称?

时间:2013-06-30 04:39:54

标签: javascript function

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
}

6 个答案:

答案 0 :(得分: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 */}
    }
    ...
}

为那些不想多思考的人编辑

这应该在函数中完成

答案 1 :(得分:2)

在javascript中没有简单的方法来获取函数的第1个或第2个或第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名称要容易得多。但是,我假设你问一个关于带有多个参数的正常函数调用的问题,这就是我上面提供的答案。

答案 2 :(得分: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将有一种方法可以一次性传递所有args,但之后只能在未来的浏览器上运行,而长时间的方式可以在浏览器中运行,现在,永远...

编辑:基于注释的更新验证例程更强一些,将文档,输入,表单,数组,正则表达式,日期和对象添加到匈牙利表示法验证例程,该例程现在也适用于窗口对象。

答案 3 :(得分: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;
}

答案 4 :(得分: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' ]

答案 5 :(得分: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)