掌握 JavaScript 函数参数
函数是一段内聚的代码,耦合在一起执行特定的任务。函数使用其参数访问外部世界。
要编写简洁高效的 JavaScript 代码,您必须掌握函数参数。
在这篇文章中,我将以有趣的示例说明 JavaScript 必须有效使用函数参数的所有功能。
函数参数
JavaScript 函数可以有任意数量的参数。让我们分别声明参数个数为 0,1 和 2 个的函数:
// 0 个参数
function zero() {
return 0
}
// 1 个参数
function identity(param) {
return param
}
// 2 个参数
function sum(param1, param2) {
return param1 + param2
}
zero() // => 0
identity(1) // => 1
sum(1, 2) // => 3
上面的 3 个函数执行了与函数声明的参数个数相同的参数。但是你可以使用少于参数个数的参数执行函数。每一种情况下 JavaScript 都没有生成任何错误。
然而,没有传入参数的参数考虑使用 undefined
值初始化。
举例来说,我们使用一个参数执行函数 sum()
(拥有两个参数):
function sum(param1, param2) {
console.log(param1) // 1
console.log(param2) // undefined
return param1 + param2
}
sum(1) // => NaN
该函数仅仅使用一个参数执行:sum(1)
。所以参数 param1
有值 1
,第二个参数 param2
使用 undefined
初始化。
param1 + param2
等价于 1 + undefined
,所以结果为 NaN
。
如果必要的话,可以总是验证如果参数是 undefined
时提供默认值。我们使 param2
的默认值为 0
:
function sum(param1, param2) {
if (param2 === undefined) {
param2 = 0
}
return param1 + param2
}
sum(1) // => 1
这里有一个更好的方法设置默认值。在下一节我们看它是如何工作。
默认参数
ES2015 默认参数功能允许使用默认值初始化参数。这是比上面例子更好且更简洁的方式。
我们使用 ES2015 默认参数设置 param2
默认为 0
:
function sum(param1, param2 = 0) {
console.log(param2) // => 0
return param1 + param2
}
sum(1) // => 1
sum(1, undefined) // => 1
在函数签名中,现在是 param2 = 0
,所以当它没有设置任何值时 param2
默认为 0
。
现在,如果该函数仅仅使用一个参数执行:sum(1)
,第二个参数将使用 0
初始化。
注意:如果你设置 undefined
为第二个参数 sum(1, undefined)
参数 param2
同样使用 0
初始化。
参数解构
我特别喜欢的是 JavaScript 函数参数的解构能力。可以行内解构对象或数组参数。
该功能在提取参数对象的一部分时很有用:
function greet({ name }) {
return `Hello, ${name}!`
}
const person = { name: 'John Smith' }
greet(person) // => 'Hello, John Smith!'
{ name }
是一个从对象解构出的参数。可以很容易组合使用默认参数和解构:
function greetWithDefault({ name = 'Unknown' } = {}) {
return `Hello, ${name}!`
}
greetWithDefault() // => 'Hello, Unknown!'
{ name = 'Unknown' } = {}
默认为一个空对象。
可以使用组合不同类型的解构的能力。举例来说,我们使用对象和数组解构在相同的参数:
function greeFirstPerson([{ name }]) {
return `Hello, ${name}!`
}
const persons = [{ name: 'John Smith' }, { name: 'Jane Doe' }]
greeFirstPerson(persons) // => 'Hello, John Smith!'
[{ name }]
参数解构更加复杂。它首先提取数组的第一项,然后读取该项的 name
属性。
参数对象
JavaScript 函数另一个好功能是使用可变数量参数执行同一函数。
如果你这样做,可以使用特别对象 arguments
,arguments
包含所有参数在一个类数组对象中。
举例来说,我们对函数参数求和:
function sumArgs() {
console.log(arguments)
// -> { 0: 5, 1: 6, length: 2 }
let sum = 0
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i]
}
return sum
}
sumArgs(5, 6) // => 11
arguments
包含函数执行时的参数。
arguments
是一个类数组对象(array-like object),所以它不能使用所有的数组方法。
另外一个不同点是每一个函数作用域声明它自己的 arguments
对象。所以可能需要额外的变量来访问外部函数作用域内的 arguments
:
function outerFunction() {
const outerArguments = arguments
return function innerFunction() {
// outFunction arguments
outerArguments[0]
}
}
箭头函数
有一个特别情况:arguments
不存在于箭头函数内。
const sumArgs = () => {
console.log(arguments)
return 0
}
// throws: "Uncaught ReferenceError: arguments is not defined"
sumArgs()
arguments
没有声明在箭头函数内。但这不是大问题。我们可以使用更高效的扩展参数来访问箭头函数的所有参数。
扩展参数(Rest parameters)
ES2015 扩展参数让你收集函数的所有参数为数组。让我们使用扩展参数对参数求和:
function sumArgs(...numbers) {
console.log(numbers) // [5, 6]
return numbers.reduce((sum, number) => sum + number)
}
sumArgs(5, 6) // => 11
扩展参数 ...numbers
保存参数到数组 [5, 6]
。由于 numbers
是数组,可以很容易使用所有数组方法。
虽然 arguments
对象不允许在箭头函数内,但扩展参数没有问题:
const sumArgs = (...numbers) => {
console.log(numbers) // [5, 6]
return numbers.reduce((sum, number) => sum + number)
}
sumArgs(5, 6) // => 11
如果不想使用扩展参数收集所有的参数,你可以自由组合使用常规参数和扩展参数。
function multiplyAndSumArgs(multiplier, ...numbers) {
console.log(multiplier) // 2
console.log(numbers) // [5, 6]
const sumArgs = numbers.reduce((sum, number) => sum + number)
return multiplier * sumArgs
}
multiplyAndSumArgs(2, 5, 6) // => 22
multiplier
是参数值的第一个常规参数,然后 ...numbers
包含所有剩余参数。
注意:每个函数最多可以有一个扩展参数。扩展参数必须位于函数参数列表的最后。
总结
除了基本用法外,JavaScript 在使用函数参数时还提供了许多有用的功能。
您可以在缺少参数时轻松地将其默认为默认值。
JavaScript 解构的所有功能都可以应用于参数。您甚至可以将解构与默认参数结合使用。
arguments
是一个类数组的特殊对象,其中包含调用该函数所用的所有参数。
作为更好的替代方法 arguments
,您可以使用扩展参数功能。它也保存参数列表,但是将它们存储到数组中。
另外,您可以将常规参数与扩展参数一起使用,但是后者必须始终在参数列表中位于最后。
本文由 吳文俊 翻译,原文地址 Let’s Master JavaScript Function Parameters