参数解构
解构还有一个特别有用的场景,即在传递函数参数时。当 JS
的函数接收大量可选参数时,一个常用模式是创建一个 options
对象,其中包含了附加的参数,就像这样:
// properties on options represent additional parameters
function setCookie(name, value, options) {
options = options || {};
let secure = options.secure,
path = options.path,
domain = options.domain,
expires = options.expires;
// code to set the cookie
}
// third argument maps to options
setCookie("type", "js", {
secure: true,
expires: 60000
});
很多 JS
的库都包含了类似于此例的 setCookie()
函数。在此函数内,name
与 value
参数是必需的,而 secure
、path
、domain
与 expires
则不是。并且因为此处对于其余数据并没有顺序要求,将它们作为 options
对象的具名属性会更有效率,而无须列出一堆额外的具名参数。这种方法很有用,但无法仅通过查看函数定义就判断出函数所期望的输入,你必须阅读函数体的代码。
参数解构提供了更清楚地标明函数期望输入的替代方案。它使用对象或数组解构的模式替代了具名参数。要看到其实际效果,请查看下例中重写版本的 setCookie()
函数:
function setCookie(name, value, { secure, path, domain, expires }) {
// code to set the cookie
}
setCookie("type", "js", {
secure: true,
expires: 60000
});
此函数的行为类似上例,但此时第三个参数使用了解构来抽取必要的数据。现在对于 setCookie()
函数的使用者来说,解构参数之外的参数明显是必需的;而可选项目存在于额外的参数组中,这同样是非常明确的;同时,若使用了第三个参数,其中应当包含什么值当然也是极其明确的。解构参数在没有传递值的情况下类似于常规参数,它们会被设为 undefined
。
参数解构拥有此前你在本章已经学过的其他解构方式的所有能力。你可以在其中使用默认参数、混合解构,或使用与属性不同的变量名。 |
解构的参数是必需的
参数解构有一个怪异点:默认情况下调用函数时未给参数解构传值会抛出错误。例如,用以下方式调用上例中的 setCookie()
函数就会出错:
// Error!
setCookie("type", "js");
调用时第三个参数缺失了,因此它不出预料地等于 undefined
。这导致了一个错误, 因为参数解构实际上只是解构声明的简写。当 setCookie()
函数被调用时,JS
引擎实际上是这么做的:
function setCookie(name, value, options) {
let { secure, path, domain, expires } = options;
// code to set the cookie
}
既然在赋值右侧的值为 null
或 undefined
时,解构会抛出错误,那么未向 setCookie()
函数传递第三个参数就同样会出错。
若你让解构的参数作为必选参数,那么上述行为并不会令人困扰。但若你要求它是可选的, 可以给解构的参数提供默认值来处理这种行为,就像这样:
function setCookie(name, value, { secure, path, domain, expires } = {}) {
// ...
}
此例为第三个参数提供了一个空对象作为其默认值。给解构的参数提供默认值,也就意味着若未向 setCookie()
函数传递第三个参数,则 secure
、path
、domain
与 expires
的值全都会是 undefined
,此时不会有错误被抛出。
参数解构的默认值
你可以为参数解构提供可解构的默认值,就像在解构赋值时所做的那样,只需在其中每个参数后面添加等号并指定默认值即可。例如:
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {}
) {
// ...
}
此代码中参数解构给每个属性都提供了默认值,所以你可以避免检查指定属性是否已被传入 (以便在未传入时使用正确的值)。而整个解构的参数同样有一个默认值,即一个空对象, 令该参数成为可选参数。这么做使得函数声明看起来比平时要复杂一些,但却是为了确保每个参数都有可用的值而付出的微小代价。