[拉勾教育-大前端高薪训练营]ES2015 函数的参数默认值与剩余参数
参数默认值
ECMAScript2015 为函数的形参列表扩展了一些有用的新语法,其中一个叫做参数默认值。在 ECMAScript2015 之前要为函数中的参数定义默认值,需要在函数体中通过逻辑代码来实现。如下代码所示:
function foo(enable) {
enable = enable || true
console.log(`foo invoked - enable: ${enable}`)
}
foo()
这里存在一个很多人经常犯错误的地方,就是很喜欢使用短路运算的方式来设置参数的默认值。实际上,这里是不能使用短路运算来设置参数的默认值的。因为使用短路运算设置参数的默认值,导致如果传递 false
也会使用默认值。如下代码所示:
function foo(enable) {
enable = enable || true
console.log(`foo invoked - enable: ${enable}`)
}
foo(false)
上述代码的运行结果如下:
foo invoked - enable: true
而正确地为参数设置默认值的方式,应该是判断参数的值是否等于 undefined
。如下代码所示:
function foo(enable) {
enable = enable === undefined ? true : enable
console.log(`foo invoked - enable: ${enable}`)
}
foo(false)
因为参数默认值的定义就是在没有传递实参时所使用的值,而没有传递实参所得到的应该是 undefined
,所以这里应该是判断参数的值是否等于 undefined
。
不过在 ECMAScript2015 新增了参数的默认值之后,这一切就变得简单得多。如下代码所示:
function foo(enable = true) {
console.log(`foo invoked - enable: ${enable}`)
}
foo(false)
这里只需要在函数的形参位置直接定义该参数的默认值即可。这个默认值只有在调用函数时没有传递实参或者实参的值为 undefined
时才会被使用。
需要注意的是,如果一个函数具有多个参数的话,那带有默认值的参数一定要在参数列表的最后,因为参数是按照次序进行传递的。如下代码所示:
function foo(enable = true, bar) {
console.log(`foo invoked - enable: ${enable}`)
console.log(`foo invoked - bar: ${bar}`)
}
foo()
上述代码的运行结果如下:
foo invoked - enable: true
foo invoked - bar: undefined
但如果调用 foo 函数时传递一个实参,这时的运行结果如下:
foo invoked - enable: false
foo invoked - bar: undefined
通过这样的测试会发现,如果带有默认值的参数没有定义在参数列表的最后的话,会导致参数的默认值无法正常工作。所以,带有默认值的参数一定要在参数列表的最后。如下代码所示:
function foo(bar, enable = true) {
console.log(`foo invoked - bar: ${bar}`)
console.log(`foo invoked - enable: ${enable}`)
}
foo(false)
上述代码的运行结果如下:
foo invoked - bar: false
foo invoked - enable: true
剩余参数
在 ECMAScript 中很多函数或方法都允许传递任意个数的参数,比如 console
的 log()
方法允许接收任意个数的参数。如下代码所示:
console.log(1, 2, 3)
对于未知个数的参数,在 ECMAScript2015 之前都是使用 arguments
对象来接收。如下代码所示:
function foo() {
console.log(arguments)
}
foo(1, 2, 3)
上述代码的运行结果如下:
{ '0': 1, '1': 2, '2': 3 }
arguments
对象实际上是一个伪数组对象。ECMAScript2015 新增了剩余参数,以 ...
为前缀的。如下代码所示:
function foo(...args) {
console.log(args)
}
foo(1, 2, 3)
上述代码的运行结果如下:
[ 1, 2, 3 ]
从上述运行的结果可以看到,剩余参数这种用法得到的是一个真实的数组,可以接收从当前位置开始到参数列表最后的所有实参。
需要注意的是,这种用法只能出现在参数列表的最后,而且只能使用一次。如下代码所示:
function foo(first, ...args) {
console.log(args)
}
foo(1, 2, 3)
上述代码的运行结果如下:
[ 2, 3 ]
如果剩余参数的位置不是在参数列表的最后,将会报错。如下代码所示:
function foo(...args, last) {
console.log(args)
}
foo(1, 2, 3)
上述代码的运行结果如下:
rest-parameter.js:19
function foo(...args, last) {
^
SyntaxError: Rest parameter must be last formal parameter
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:599:28)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
如果剩余参数使用多次的话,也会报出与上述结果一样的错误。
展开数组
...
除了可以作为函数的剩余参数的 Rest
用法,还有一种用来展开的 Spread
用法。展开这种用法的用途有很多,这里先来掌握与函数相关的数组参数展开。
比如定义一个数组,通过 console.log()
方法依次打印这个数组中的成员。那最笨的方法就是通过索引值访问数组中的每一个成员。如下代码所示:
const arr = ['foo', 'bar', 'baz']
console.log(arr[0], arr[1], arr[2])
如果数组中成员的个数是不固定的话,这样通过索引值访问数组中所有的成员这种方式就行不通了。在 ECMAScript2015 之前通常是通过 apply()
方法来解决这个问题。如下代码所示:
const arr = ['foo', 'bar', 'baz']
console.log.apply(console, arr)
ECMAScript2015 之后就可以使用 ...
用法来展开数组,从而得到数组中每一个成员。如下代码所示:
const arr = ['foo', 'bar', 'baz']
console.log(...arr)
这种方式会将数组中的成员按照次序传递给函数。