2013-06-30 109 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