可能 JavaScript 最常见的一个技巧就是关于设定函数参数默认值的。多年以来我们实现这一点的方式是这样的,看起来应该很熟悉:
function foo(x,y) {
x = x || 11;
y = y || 31;
console.log( x + y );
}
foo(); // 42
foo( 5, 6 ); // 11
foo( 5 ); // 36
foo( null, 6 ); // 17
当然,如果你之前使用过这个模式,就会知道它很有用,但同时又有点危险,比如,如果对于一个参数你需要能够传入被认为是 false (假)的值。考虑:
foo( 0, 42 ); // 53 <--哎呀,并非42
为什么?因为这里 0 为假,所以 x || 11 结果为 11 ,而不是直接传入的 0 。
要修正这个问题,有些人会选择增加更多的检查,就像下面这样:
function foo(x,y) {
x = (x !== undefined) ? x : 11;
y = (y !== undefined) ? y : 31;
console.log( x + y );
}
foo( 0, 42 ); // 42
foo( undefined, 6 ); // 17
当然,这意味着除了 undefined 之外的任何值都可以直接传入。然而, undefined 会表达“我没有传入信息”这样的信息。除非你确实需要能够传入 undefined ,它就工作的很好。
这种情况下,可以通过它并不存在于数组 arguments 之中来确定这个参数是被省略的,可能就像下面这样
function foo(x,y) {
x = (0 in arguments) ? x : 11;
y = (1 in arguments) ? y : 31;
console.log( x + y );
}
foo( 5 ); // 36
foo( 5, undefined ); // NaN
但是如果你不能传递任何值(甚至 undefined 也不行)来表明“我省略了这个参数”,那么如何省略第一个参数 x 呢?foo(,5) 很吸引人,但这是不合法的语法。
foo.apply(null, [,5]) 看来可以实现这个技巧,但是这里 apply(..) 的诡异实现意味着这些参数被当作了 [undefined,5] ,这当然不是一个省略。
如果继续深入的话,就会发现你只能通过传入比“期望”更少的参数来省略最后的若干参数(例如,右侧的),而无法省略位于参数列表中间或者起始处的参数。这里应用了一个很重要的需要记住的 JavaScrpt 设计原则: undefined 意味着缺失。也就是说, undefined 和缺失是无法区别的,至少对于函数参数来说是如此。
了解了所有这些之后,现在我们可以讨论 ES6 新增的一个有用的语法来改进为缺失参数赋默认值的流程
function foo(x = 11, y = 31) {
console.log( x + y );
}
foo(); // 42
foo( 5, 6 ); // 11
foo( 0, 42 ); // 42
foo( 5 ); // 36
foo( 5, undefined ); // 36 <-- 丢了undefined
foo( 5, null ); // 5 <-- null被强制转换为0
foo( undefined, 6 ); // 17 <-- 丢了undefined
foo( null, 6 ); // 6 <-- null被强制转换为0
注意这些结果,以及它们和前面的方法之间的微妙区别和相似之处。