2013-06-30 110 views
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函数中所有参数的名称。如果此函数中的任何参数都是未定义的,那么我希望该函数抛出一个列出缺少参数名称的错误。如何获取JavaScript函数中缺少参数的名称?

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

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 
} 
+0

你不需要'|| (长度==“未定义”)'的一部分,除非你担心有人可能会打电话给你的功能,实际上故意通过用'fnDrawPrism(“未定义”)'该字符串。 – nnnnnn

+0

你认为[参数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments)可以解决你的问题 – aaronman

+1

@aaronman是的,但后来我需要一个从arguments数组中获取每个参数的名称的方法。 –

回答

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将有一种方法可以一次性传递所有参数,但那样只会在未来的浏览器上运行,而长时间的浏览器则可以在浏览器中运行,然后,现在和永远......

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

+2

看起来有人只是低估了这个问题,没有明显的原因。对于我在这个问题(及其答案)中看到的所有随机低估,我感到非常困惑。 –

+1

你可以告诉它不是我... – dandavis

+0

供参考:要测试一个对象是否是一个数组,最好的技巧来自http://www.ecma-international.org/ecma-262/5.1/#sec- 15.2.4.2:'{} .toString.call([])。replace(/^\ [object \ s +(。*)\] $ /,'$ 1')==='Array'' – SheetJS

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 */} 
    } 
    ... 
} 

编辑不想认为谁的人多一点点

这应该在功能中完成

+2

这意味着彻底改变了API;更糟糕的是,imo。 – naomik

+2

在功能! – shift66

+1

@naomik在这里更改哪个API? –

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/


如果你想调整你的代码,并通过与键/值的单个对象作为参数,那么迭代它们并从传递的对象键获取参数名称会更容易。但是,我假设你问了一个关于具有多个参数的正常函数调用的问题,所以这是我在上面提供的答案。

+1

为什么downvote? – jfriend00

+1

我认为这里有一个语法错误:当我尝试运行这个函数时,我在浏览器控制台中得到了'Uncaught SyntaxError:Unexpected identifier'。 –

+0

@AndersonGreen - 固定为'或'的语法错误。 – jfriend00

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' ] 
+0

为什么downvote? – SheetJS

+2

我怀疑这个问题的答案已被串行downvoter攻击。答案发布后,几乎对这个问题的每个答案都是立即下调的。 –

0

在我看来一个更通用的“说法二是缺少”类型的异常是足够的 - 开发商看到这样的异常,然后会去检查什么论据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)

+2

似乎几乎每个这个问题的新答案都被低估了。这里发生了什么? :/ –

+0

我认为这也是不公平的。正如我在前面的评论中所说的,我认为你的目标是过度的,但是仍然要弄清楚如何做到这一点很有趣,所以我实际上已经提出了这个问题。我的回答很快就被低估了,我不认为相关人员甚至可以彻底阅读。无论如何,我已经围绕着StackOverflow足够长的时间来看到这种情况,所以我不会让它困扰我。 – nnnnnn

+0

我讨厌人们在不解释自己的情况下倒下事物。我对此表示赞同,因为它采用了*而非*将参数存储在额外数组或对象中的有趣方法,并且很好地解释了它。对你感到羞耻,沮丧! –

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; 
} 
+0

+1 - 不确定为什么其他人低估了这一点。看起来像一个有趣的解决方案给我。 – jfriend00

+1

@ jfriend00回答这个问题的危险之一似乎是你得到了一个自动downvote。 – jcsanyi

+1

是的,它似乎对这个问题的每个答案都至少有一个downvote。 – jfriend00