现在,我已经看到了两种确定参数是否已传递给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');
据我所知,它们都导致相同的结果,但是我在生产中只使用了第一个。
汤姆提到的另一个选择:
function Test(argument1, argument2) {
if(argument2 === null) {
argument2 = 'blah';
}
alert(argument2);
}
根据Juan的评论,最好将Tom的建议更改为:
function Test(argument1, argument2) {
if(argument2 === undefined) {
argument2 = 'blah';
}
alert(argument2);
}
有几种方法可以检查参数是否传递给函数。除了您在(原始)问题中提到的两个-检查arguments.length
或使用||
运算符提供默认值外,还可以显式检查undefined
via的参数argument2 === undefined
或typeof argument2 === 'undefined'
一个是否偏执(请参阅注释)。
使用||
运营商已经成为标准做法-所有时尚的年轻人做到这一点-但要小心:默认值将被触发,如果该参数的计算结果为false
,这意味着它实际上可能是undefined
,null
,false
,0
,''
(或任何其他为它Boolean(...)
的回报false
)。
所以问题是何时使用哪种检查,因为它们都会产生略有不同的结果。
检查arguments.length
表现出“最正确”的行为,但如果有多个可选参数,则可能不可行。
undefined
下一个“最佳”测试-仅在使用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的extend方法。
function foo(options) {
default_options = {
timeout : 1000,
callback : function(){},
some_number : 50,
some_text : "hello world"
};
options = $.extend({}, default_options, options);
}
如果调用该函数,则如下所示:
foo({timeout : 500});
然后,options变量将是:
{
timeout : 500,
callback : function(){},
some_number : 50,
some_text : "hello world"
};
这是我找到测试的少数情况之一:
if(! argument2) {
}
工作得很好,并且在句法上带有正确的含义。
(由于同时存在限制,我不允许使用argument2
具有其他含义的合法null值;但这确实很令人困惑。)
编辑:
这是松散类型语言和强类型语言之间风格差异的一个很好的例子。以及javascript提供的黑体风格选项。
我个人的偏爱(没有批评意味其他偏爱)是极简主义。只要我保持一致和简洁,代码所需要说的就越少,其他人理解正确地推断出我的意思的理解就越少。
这种偏好的一个含义是,我不想-觉得没有用-堆积了很多类型依赖测试。相反,我尝试使代码表示其含义。并只测试我真正需要测试的东西。
我在其他人的代码中发现的麻烦之一是需要弄清楚他们是否期望在更大的范围内实际遇到他们正在测试的案例。或者,如果他们试图测试所有可能的东西,则可能是他们没有完全完全预期上下文。这意味着我最终需要在两个方向上都进行详尽的跟踪,然后才能自信地重构或修改任何内容。我认为,他们很有可能已经进行了各种测试,因为他们预见了需要这些测试的情况(通常对我而言这并不明显)。
(我认为这些人使用动态语言的方式存在严重的弊端。很多时候,人们不想放弃所有静态测试,而最终伪造它。)
在将全面的ActionScript 3代码与优雅的javascript代码进行比较时,我最明显地看到了这一点。AS3可以是js的3到4倍,而我怀疑可靠性至少没有提高,仅是因为所做出的编码决策数量(3-4X)。
如您所说,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将转换undefined
,null
,0
,和""
成布尔false
。如果你使用汤姆的方法,只有第四次试验将使用默认的!
您选择哪种方法实际上取决于您的预期行为。如果undefined
不允许使用以外的其他值argument2
,那么您可能会希望第一个有所不同;如果需要一个非零,非空,非空的值,则第二种方法是理想的-实际上,它通常用于快速消除考虑范围如此之大的值。
url = url === undefined ? location.href : url;
在ES6(ES2015)中,可以使用默认参数
function Test(arg1 = 'Hello', arg2 = 'World!'){
alert(arg1 + ' ' +arg2);
}
Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!
抱歉,我仍然无法评论,所以要回答汤姆的答案...在javascript中(未定义!= null)== false实际上,该函数无法使用“ null”,您应该使用“ undefined”
为什么不使用!!
运算符?该运算符位于变量之前,将其转换为布尔值(如果我理解得很好),因此!!undefined
and !!null
(甚至!!NaN
,这可能很有趣)将返回false
。
这是一个例子:
function foo(bar){
console.log(!!bar);
}
foo("hey") //=> will log true
foo() //=> will log false
通过调用具有可选属性的Object的函数可以方便地进行参数检测:
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]; }
}
}
}
}
查找参数是否传递给函数还有一种棘手的方法。看下面的例子:
this.setCurrent = function(value) {
this.current = value || 0;
};
这是必需的,这意味着如果value
不存在/不传递的值,则将其设置为0。
太酷了吧!
有时,您可能还需要检查类型,特别是在将函数用作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;
}
}
}
}
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
。考虑让世界变得更美好。
fnCalledFunction(Param1,Param2,window.YourOptionalParameter)
如果从许多地方调用了上述函数,并且您确定从每个位置都传递了前两个参数,但是不确定第三个参数,则可以使用window。
如果未通过调用方方法定义window.param3,则它将进行处理。
文章标签:arguments , javascript
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!