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

如何最好地确定参数是否未发送到JavaScript函数,javascript,arguments,Javascript,Arguments,我现在看到了两种确定参数是否已传递给JavaScript函数的方法。我想知道是一种方法比另一种好,还是一种方法不好用 function Test(argument1, argument2) { if (Test.arguments.length == 1) argument2 = 'blah'; alert(argument2); } Test('test'); 或 据我所知,它们产生的结果是一样的,但我以前在生产中只使用过第一个 另一种选择是: 根据Juan

我现在看到了两种确定参数是否已传递给JavaScript函数的方法。我想知道是一种方法比另一种好,还是一种方法不好用

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

      alert(argument2);
 }

 Test('test');

据我所知,它们产生的结果是一样的,但我以前在生产中只使用过第一个

另一种选择是:

根据Juan的评论,最好将Tom的建议改为:

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

    alert(argument2);
}

检查参数是否传递给函数有几种不同的方法。除了您在(原件)中提到的两个问题-检查
arguments.length
或使用
|
运算符提供默认值-如果一个人患有偏执症,还可以通过
argument2===undefined
typeof argument2==='undefined'
明确检查
未定义的
参数(参见注释)

使用
| |
操作符已成为标准做法-所有酷孩子都会这样做-但要小心:如果参数的计算结果为
false
,则会触发默认值,这意味着它实际上可能是
未定义的
空的
假的
0
'
(或
Boolean(…)
返回
false
的任何其他内容)

所以问题是什么时候使用哪种检查,因为它们产生的结果都略有不同

检查
参数。length
显示“最正确”的行为,但如果有多个可选参数,则可能不可行

undefined
的测试是下一个“最佳”-只有在使用
undefined
值显式调用函数时才会“失败”,这很可能与忽略参数的方式相同

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

总结一下:只有当你知道自己在做什么时才使用它

在我看来,如果有多个可选参数,并且不希望传递对象文本作为命名参数的解决方法,那么使用
|
也是一种方法

另一种使用
参数提供默认值的好方法。通过遍历switch语句的标签,可以使用length

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
}

这样做的缺点是程序员的意图(视觉上)不明显,并且使用“幻数”;因此可能容易出错。

对不起,我仍然无法评论,所以要回答Tom的答案。。。 在javascript中(未定义!=null)==false
事实上,函数不能与“null”一起工作,您应该使用“undefined”

这是我发现测试的少数情况之一:

if(! argument2) {  

}
非常好地工作,并且在语法上具有正确的含义

(同时还有一个限制,即我不允许
argument2
使用合法的空值,因为它有其他含义;但这会让非常困惑。)

编辑:

这是松散类型语言和强类型语言在风格上差异的一个很好的例子,也是javascript提供的一个风格选项

我的个人偏好(没有针对其他偏好的批评)是极简主义。只要代码说得越少,只要我保持一致和简洁,其他人就越不需要理解才能正确推断我的意思

这种偏好的一个含义是,我不想——也不觉得它有用——堆积一堆类型依赖性测试。相反,我试图让代码的含义与它看起来的相同;并且只测试我真正需要测试的内容

我在其他一些人的代码中发现的一个问题是,他们需要弄清楚,在更大的上下文中,他们是否期望实际遇到他们正在测试的情况。或者,如果他们试图测试所有可能的情况,他们可能对上下文的预测不够充分。这意味着我最终需要这样做在我能够自信地重构或修改任何东西之前,我想他们很有可能已经将这些不同的测试放在适当的位置,因为他们预见到了需要它们的环境(而我通常并不清楚)

(我认为这些人使用动态语言的方式有一个严重的缺点。人们往往不想放弃所有的静态测试,最终假装)。 在比较全面的ActionScript3代码和优雅的javascript代码时,我最清楚地看到了这一点。AS3的容量可能是js的3到4倍,我怀疑其可靠性至少不会更好,这仅仅是因为所做的编码决策的数量(3-4倍)


正如您所说,Shog9,YMMV.:D

存在显著差异。让我们设置一些测试用例:

var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");
对于您描述的第一个方法,只有第二个测试将使用默认值。第二个方法将默认除第一个以外的所有方法(因为JS将转换
未定义的
空的
0
转换为布尔值
false
。如果使用Tom的方法,只有第四个测试将使用默认值


选择哪种方法实际上取决于您的预期行为。如果
argument2
允许使用
未定义的
以外的值,那么您可能需要对第一种方法进行一些更改;如果需要非零、非空、非空的值,那么第二种方法是理想的-事实上,它通常用于快速消除此类错误可考虑的值范围很广。

通过使用可选属性的对象调用函数,可以方便地进行参数检测:

url = url === undefined ? location.href : url;
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]; }
            }
        }
    }
}

如果您使用jQuery,一个不错的选项(特别是对于复杂的情况)是
url = url === undefined ? location.href : url;
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]; }
            }
        }
    }
}
function foo(options) {

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

    options = $.extend({}, default_options, options);
}
foo({timeout : 500});
{
    timeout : 500,
    callback : function(){},
    some_number : 50,
    some_text : "hello world"
};
function foo(bar){
    console.log(!!bar);
}

foo("hey") //=> will log true

foo() //=> will log false
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;
            }
        }
    }
}
this.setCurrent = function(value) {
  this.current = value || 0;
};