如何最好地确定参数是否未发送到JavaScript函数

我现在已经看到了两个方法来确定一个参数是否已经传递给一个JavaScript函数。 我想知道如果一种方法比另一种好,或者只是不好用?

function Test(argument1, argument2) { if (Test.arguments.length == 1) argument2 = 'blah'; alert(argument2); } Test('test'); 

要么

  function Test(argument1, argument2) { argument2 = argument2 || 'blah'; alert(argument2); } Test('test'); 

据我所知,它们都是同样的东西,但我以前只用了第一个。

Tom提到的另一个选项:

 function Test(argument1, argument2) { if(argument2 === null) { argument2 = 'blah'; } alert(argument2); } 

按照胡安的评论,把汤姆的build议改为:

 function Test(argument1, argument2) { if(argument2 === undefined) { argument2 = 'blah'; } alert(argument2); } 

有几种不同的方法来检查参数是否传递给一个函数。 除了你在(原始)问题中提到的两个 – 检查arguments.length或使用|| 运算符提供默认值 – 也可以通过argument2 === undefinedtypeof argument2 === 'undefined'显式检查undefined的参数,如果一个是偏执的(请参阅注释)。

使用|| 操作符已经成为标准操作 – 所有酷的孩子都这样做 – 但要小心:如果参数的计算结果为false ,这意味着它可能实际上是undefinednullfalse0 ,或者其他任何东西Boolean(...)返回false )。

所以问题是何时使用哪种检查,因为它们都会产生稍微不同的结果。

检查arguments.lengthperformance出“最正确的”行为,但如果有多个可选参数,则可能不可行。

undefined的testing接下来是“最好的” – 如果函数被明确地调用了一个undefined值,那么它只是“失败”,在所有可能的情况下,应该像忽略参数一样对待。

使用|| 运算符可能会触发使用默认值,即使提供了有效的参数。 另一方面,其行为实际上可能是需要的。

总结: 只有在你知道自己在做什么的时候才使用它!

在我看来,使用|| 如果有多个可选参数并且不想传递一个对象字面量作为命名参数的解决方法,那么也是这样的方法。

使用arguments.length提供默认值的另一个好方法是通过使用switch语句的标签:

 function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) { switch(arguments.length) { case 1: optionalArg1 = 'default1'; case 2: optionalArg2 = 'default2'; case 3: optionalArg3 = 'default3'; case 4: break; default: throw new Error('illegal argument count') } // do stuff } 

这有一个缺点,程序员的意图不是(视觉上)明显的,并使用“神奇的数字”; 因此可能容易出错。

如果你使用的是jQuery,那么一个好的选项(特别是对于复杂的情况)就是使用jQuery的扩展方法 。

 function foo(options) { default_options = { timeout : 1000, callback : function(){}, some_number : 50, some_text : "hello world" }; options = $.extend({}, default_options, options); } 

如果你调用这个函数,就像这样:

 foo({timeout : 500}); 

选项variables将是:

 { timeout : 500, callback : function(){}, some_number : 50, some_text : "hello world" }; 

这是我findtesting的less数情况之一:

 if(! argument2) { } 

作品非常好,语法上带有正确的含义。

(同时限制,我不会允许一个合法的null值为argument2有其他的意义,但这将是非常混乱。)

编辑:

这是松散types和强types语言之间风格差异的一个很好的例子; 以及JavaScript提供的黑色风格选项。

我个人的偏好(没有其他偏好的批评)是极简主义。 代码越less,只要我保持一致和简洁,就越不需要别人去正确地理解我的意思。

这种偏好的一个含义是,我不希望 – 堆积一堆types依赖性testing,不觉得有用。 相反,我试图让代码意味着它的外观。 并只testing我真正需要testing的东西。

我在一些其他民族的法典中find的一个加重之处是需要弄清楚他们是否期望在更大的范围内真正地遇到他们正在testing的案例。 或者,如果他们试图对所有可能的事情进行testing,那么他们就没有足够的预测上下文。 这意味着我最终需要在两个方向上彻底地追踪它们,然后才能自信地重构或修改任何东西。 我认为,他们很可能已经进行了各种各样的testing,因为他们预见到了他们需要的情况(而这对我来说通常是不明显的)。

(我认为这些人使用dynamic语言的方式是一个严重的缺点,人们往往不愿意放弃所有的静态testing,最终会伪造它。)

我最明显地看到,比较全面的ActionScript 3代码与优雅的JavaScript代码。 AS3可以是js的3到4倍,而我怀疑的可靠性至less不会好,只是因为编码决定的数量(3-4X)。

正如你所说,Shog9,YMMV。 :d

有显着的差异。 我们来设置一些testing用例:

 var unused; // value will be undefined Test("test1", "some value"); Test("test2"); Test("test3", unused); Test("test4", null); Test("test5", 0); Test("test6", ""); 

用你描述的第一种方法,只有第二个testing将使用默认值。 第二种方法将默认除第一个以外(因为JS会将undefinednull0""转换为布尔值false 。如果您要使用Tom的方法,则只有第四个testing会使用默认值!

您select哪种方法确实取决于您的预期行为。 如果argument2以外的值可以被允许,那么你可能会想要在第一个variables。 如果需要一个非零的,非空的非空值,那么第二种方法是理想的 – 实际上,它通常用于快速消除如此大范围的值。

 url = url === undefined ? location.href : url; 

对不起,我还没有评论,所以要回答汤姆的答案…在JavaScript(undefined!= null)== false事实上,该函数不会与“空”工作,你应该使用“未定义”

通过使用可选属性对象唤起您的函数来处理参数检测可能很方便:

 function foo(options) { var config = { // defaults list: 'string value', of: [a, b, c], optional: {x: y}, objects: function(param){ // do stuff here } }; if(options !== undefined){ for (i in config) { if (config.hasOwnProperty(i)){ if (options[i] !== undefined) { config[i] = options[i]; } } } } } 

为什么不使用!! 运营商? 这个运算符放在variables之前,把它变成一个布尔值(如果我已经很好理解了),那么!!undefined!!null (甚至!!NaN ,这可能会非常有趣)将返回false

这是一个例子:

 function foo(bar){ console.log(!!bar); } foo("hey") //=> will log true foo() //=> will log false 

有时你也可能想要检查types,特别是如果你使用函数作为getter和setter。 以下代码是ES6(不会在EcmaScript 5或更旧版本中运行):

 class PrivateTest { constructor(aNumber) { let _aNumber = aNumber; //Privileged setter/getter with access to private _number: this.aNumber = function(value) { if (value !== undefined && (typeof value === typeof _aNumber)) { _aNumber = value; } else { return _aNumber; } } } } 

在ES6(ES2015)中,您可以使用默认参数

 function Test(arg1 = 'Hello', arg2 = 'World!'){ alert(arg1 + ' ' +arg2); } Test('Hello', 'World!'); // Hello World! Test('Hello'); // Hello World! Test(); // Hello World! 

有一个棘手的方法,以及发现,参数是否传递给一个函数 。 看看下面的例子:

 this.setCurrent = function(value) { this.current = value || 0; }; 

这个必要的意思是,如果值的value不存在/通过 – 将其设置为0。

很酷很棒!