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

时间:2009-01-04 17:38:58

标签: javascript arguments

我现在已经看到了两种确定参数是否已传递给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);
}

根据胡安的评论,将汤姆的建议改为:

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

    alert(argument2);
}

13 个答案:

答案 0 :(得分:261)

有几种不同的方法可以检查参数是否传递给函数。除了您在(原始)问题中提到的两个问题 - 检查arguments.length或使用||运算符提供默认值 - 还可以通过{{显式检查undefined的参数1}}或argument2 === undefined如果一个人偏执(见评论)。

使用typeof argument2 === 'undefined'运算符已成为标准做法 - 所有酷孩子都会这样做 - 但要小心:如果参数的计算结果为||,则会触发默认值,这意味着它可能实际上是falseundefinednullfalse0(或''返回Boolean(...)的任何其他内容)。

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

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

arguments.length的测试接下来是“最好的” - 如果使用undefined值明确调用该函数,它只会'失败',在所有可能的情况下,应该将其视为省略参数。

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

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

在我看来,如果有多个可选参数,并且不希望将对象文字作为命名参数的变通方法传递,则使用||也是一种方法。

使用||提供默认值的另一种好方法是通过掉落switch语句的标签来实现:

arguments.length

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

答案 1 :(得分:16)

如果您正在使用jQuery,那么一个很好的选项(特别是对于复杂的情况)是使用jQuery's extend method

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"
};

答案 2 :(得分:13)

这是我找到测试的少数情况之一:

if(! argument2) {  

}

工作得非常好,并在句法上带有正确的含义。

(同时限制我不允许argument2的合法空值具有其他一些含义;但这会真的令人困惑。)

编辑:

这是松散类型和强类型语言之间风格差异的一个很好的例子;以及javascript在黑桃中提供的风格选项。

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

这种偏好的一个含义是,我不想 - 不要觉得它有用 - 堆积一堆类型依赖性测试。相反,我试图让代码意味着它的意思;并仅测试我真正需要测试的内容。

我在其他一些人的代码中发现的一个加剧是需要弄清楚他们是否期望在更大的背景下实际遇到他们正在测试的案例。或者,如果他们试图测试所有可能的事情,那么他们就不会完全预测上下文。这意味着在我能够自信地重构或修改任何内容之前,我最终需要在两个方向上详尽地跟踪它们。我认为他们很可能已经进行了各种各样的测试,因为他们预见到需要这些测试的情况(通常对我来说并不明显)。

(我认为这些人使用动态语言的方式存在严重的缺点。人们常常不想放弃所有静态测试,最终伪造它。)

在将全面的ActionScript 3代码与优雅的javascript代码进行比较时,我最为明显地看到了这一点。 AS3可以是js的3或4倍,我怀疑的可靠性至少不会更好,只是因为编码决策的数量(3-4X)。

如你所说,Shog9,YMMV。 :d

答案 3 :(得分:7)

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

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

使用您描述的第一种方法,只有第二种测试将使用默认值。第二种方法将默认除第一种方法之外的所有方法(因为JS会将undefinednull0""转换为布尔值false。如果你是使用汤姆的方法,只有第四个测试将使用默认值!

您选择哪种方法实际上取决于您的预期行为。如果undefined允许argument2以外的值,那么您可能希望第一个有一些变化;如果需要非零,非空,非空值,那么第二种方法是理想的 - 实际上,它通常用于快速消除如此广泛的值。

答案 4 :(得分:6)

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

答案 5 :(得分:4)

在ES6(ES2015)中,您可以使用Default parameters



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

Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!




答案 6 :(得分:3)

对不起,我还是无法发表评论,所以回答汤姆的回答...... 在javascript(undefined!= null)== false 事实上,该函数不能使用“null”,您应该使用“undefined”

答案 7 :(得分:2)

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

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]; }
            }
        }
    }
}

答案 8 :(得分:2)

为什么不使用!!运算符?放在变量之前的这个运算符将它转换为布尔值(如果我已经很好理解),那么!!undefined!!null(甚至是!!NaN,这可能非常有趣)将返回false

这是一个例子:

function foo(bar){
    console.log(!!bar);
}

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

foo() //=> will log false

答案 9 :(得分:1)

有时您可能还想检查类型,特别是如果您使用此函数作为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;
            }
        }
    }
}

答案 10 :(得分:0)

有一个tricky way as well to find, whether a parameter is passed to a function or not。看看下面的例子:

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

这必要意味着如果value的值不存在/通过 - 将其设置为0.

非常酷啊!

答案 11 :(得分:0)

function example(arg) {
  var argumentID = '0'; //1,2,3,4...whatever
  if (argumentID in arguments === false) {
    console.log(`the argument with id ${argumentID} was not passed to the function`);
  }
}

因为数组继承自Object.prototype。考虑⇑使世界变得更美好。

答案 12 :(得分:-1)

fnCalledFunction(Param1,Param2,window.YourOptionalParameter)

如果从许多地方调用了上述函数,并且您确定从每个位置都传递了前两个参数,但是不确定第三个参数,那么您可以使用window。

window.param3将在未通过调用方方法定义的情况下进行处理。