☰
jstips 第 43 期:在函数参数中使用解构赋值(Destructuring in Function Parameters)
2026/10/8 1:45:10 网站建设 项目流程
  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载

导读

本篇基于 jstips 仓库第 43 期技巧(对应文件 _posts/es_ES/javascript/2016-02-12-use-destructuring-in-function-parameters.md,英文版见 _posts/en/javascript/2016-02-12-use-destructuring-in-function-parameters.md),讲解如何在函数参数位置直接使用 ES6 解构赋值(Destructuring Assignment),让"接收 options 对象"的函数签名变得声明式、可读、自解释。读完你将掌握:参数级解构的写法、与默认参数(Default Parameters)的组合技巧、参数缺失/类型错误等边界情况的正确处理,以及它在 Node.js 中的可用性与历史限制。

参数解构:把对象参数直接"拆开"

很多开发者早已熟悉 ES6 的解构赋值语法——它让我们可以从数组或对象中一次性提取多个值。但鲜为人知的是,解构语法同样可以直接写在函数的参数列表里:

var sayHello = function({ name, surname }) { console.log(`Hello ${name} ${surname}! How are you?`); }; sayHello({ name: 'John', surname: 'Smith' }) // -> Hello John Smith! How are you?

当调用方传入{ name: 'John', surname: 'Smith' }时,参数列表中的{ name, surname }会立即把该对象的name与surname两个属性"拆"成两个局部变量,函数体内部无需再写params.name、params.surname。

这种写法最典型的应用场景,就是接收一个 options/配置对象的函数:函数签名直接暴露它需要的字段,而不是一个不透明的options对象,调用方一眼就能看出契约。

叠加默认参数:调用方留空的字段自动填充

对于"可选项很多、调用方经常只传其中一部分"的 options 对象场景,可以让解构与默认参数协同工作,把调用方省略(或忘传)的字段自动填充为默认值:

var sayHello2 = function({ name = "Anony", surname = "Moose" } = {}) { console.log(`Hello ${name} ${surname}! How are you?`); };

逐段拆解这个签名:

  • { name = "Anony", surname = "Moose" }:声明解构目标对象,并对name、surname两个属性分别给出默认值;
  • = {}:为整个解构参数声明默认值为空对象{}——当调用方完全没传参数,或传入了错误类型(见下文"参数处理")时,就改用{}作为解构来源,从而避免运行时崩溃。

实际调用效果:

sayHello2() // -> Hello Anony Moose! How are you? sayHello2({ name: "Bull" }) // -> Hello Bull Moose! How are you?

注意一个细节:sayHello2({ name: "Bull" })只传了name,此时surname属性缺失,便由默认值"Moose"顶上。这正是"属性级默认值"与"整体对象默认值"两层防护的配合。

参数处理:边界情况与防御性写法

普通解构下的undefined泄漏

如果不使用任何默认值,当传入对象缺少函数签名中声明的字段时,未匹配到的参数一律为undefined,需要调用方自行兜底:

var sayHelloTimes = function({ name, surname }, times) { console.log(`Hello ${name} ${surname}! I've seen you ${times} times before.`); } sayHelloTimes({ name: "Pam" }, 5678) // -> Hello Pam undefined! I've seen you 5678 times before. sayHelloTimes(5678) // -> Hello undefined undefined! I've seen you undefined times before.

整个参数缺失:直接抛 TypeError

更糟糕的情况是:需要被解构的那个参数根本没传。此时解构无从谈起,函数直接抛出异常,可能导致整个应用崩溃:

sayHelloTimes() // -> Uncaught TypeError: Cannot match against 'undefined' or 'null'...

从概念上讲,这类似于访问一个未定义对象的属性——都是对undefined/null取值,只是异常类型不同。这提醒我们:只要函数签名中有解构参数,就必须考虑"一个参数都不传"的调用路径。

属性默认值 + 对象默认值:双保险

为解构参数同时加上属性级默认值和整体= {}默认值,可以把上述问题大部分掩盖掉:

var sayHelloTimes2 = function({ name = "Anony", surname = "Moose" } = {}, times) { console.log(`Hello ${name} ${surname}! I've seen you ${times} times before.`); }; sayHelloTimes2({ name: "Pam" }, 5678) // -> Hello Pam Moose! I've seen you 5678 times before. sayHelloTimes2(5678) // -> Hello Anony Moose! I've seen you undefined times before. sayHelloTimes2() // -> Hello Anony Moose! I've seen you undefined times before.

对照三种调用可以看到:= {}覆盖了"整个对象缺失"的情形,而属性默认值覆盖了"对象存在但个别属性缺失"的情形——两者职责互补。

只加属性默认值、不加对象默认值:仍会崩溃

如果把整体= {}去掉,只保留属性级默认值,那么"对象缺失"这一层防护就没了:

var sayHelloTimes2a = function({ name = "Anony", surname = "Moose" }, times) { console.log(`Hello ${name} ${surname}! I've seen you ${times} times before.`); }; sayHelloTimes2a({ name: "Pam" }, 5678) // -> Hello Pam Moose! I've seen you 5678 times before. sayHelloTimes2a(5678) // -> Hello Anony Moose! I've seen you undefined times before. sayHelloTimes2a() // -> Uncaught TypeError: Cannot match against 'undefined' or 'null'.

从最后一行可以看到,sayHelloTimes2a()依旧抛出TypeError。原文档的结论非常明确:属性级默认值只对"属性缺失"负责,只有= {}这类整体对象默认值才能兜住"对象本身缺失"的极端调用。

可用性与历史限制

需要注意,解构赋值并非在写作时(2016 年前后)的所有运行环境中默认可用:

  • 在当时的 Node.js 中,解构赋值可能默认未开启。若想提前体验,可在启动时显式传入 Harmony 标志:
node --harmony-destructuring your_script.js
  • 在浏览器端,当时的支持情况也参差不齐,建议实际部署前先在目标运行环境验证。

上述"可用性"信息以原文档写作时(tip 43,对应 2016 年 2 月)为背景。如今的主流 Node.js 版本与浏览器早已原生支持参数解构与默认参数,--harmony-destructuring标志仅用于理解这段演进历史。对于现代运行环境,请以当前环境的实测结果为准。

与仓库内其他 ES6 技巧的呼应

参数解构与默认参数是 ES6 参数体系的两块基石,本仓库中还有几期技巧与之直接相关,建议对照阅读:

  • Tip 12「ES6 函数中的伪必填参数」(_posts/en/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md):利用默认参数"未传值时执行默认表达式"的特性,让_err(...)这类抛错函数成为默认值,从而把参数从"可选的"变成"伪必填的"。这与本期的"属性默认值填充"形成互补——默认值既可以兜底,也可以主动报错。
  • Tip 44「了解传值机制」(_posts/en/javascript/2016-02-13-know-the-passing-mechanism.md):理解对象参数是"按引用值传递(call-by-sharing)",有助于把握解构拿到的是引用还是副本,避免在解构后误改调用方对象。
  • Tip 54「如何在函数中使用可选参数(含可选回调)」(_posts/en/javascript/2016-05-06-use-optional-arguments.md):展示了不用解构时,通过arguments/剩余参数手动解析可选参数的传统写法;与本期写法对比,更能体会参数解构在可读性上的优势。

此外,本期技巧在仓库中还有 简体中文版 与 繁体中文版,可作为双语对照阅读。

小结

一句话概括本期技巧:当函数需要接收 options 对象时,直接在参数列表里解构它——配合属性级默认值与= {}整体默认值,就能用最少的代码写出既自解释、又对边界情况健壮(不传参、少传属性、传错类型)的函数签名。撰写健壮的库 API 时,这套"参数解构 + 双层默认值"的组合是值得优先采用的模式。

  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载

相关推荐

上一篇:如何让老旧电视焕发新生?MyTV-Android电视直播软件使用指南
下一篇:3步构建高性能Android电视直播应用:MyTV-Android技术实践指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询