可选链 `?.`——再也不用写一长串 `&&` 了!

引言

"Cannot read property 'name' of undefined------又是这个错!我明明已经写了 if (user && user.profile && user.profile.name) 啊!"

同事凑过来看了一眼:"你只检查了 user 和 user.profile,但没检查 user.profile.name 本身?哦,其实 user.profile.name 不可能是 undefined 的......等等,如果 user.profile 是空对象呢?"

我陷入了沉思:难道我要写 user && user.profile && user.profile.name && user.profile.name.firstName?这代码长得像铁轨,谁看得懂啊!

直到有一天,我发现了可选链操作符 ?.。它就像一把瑞士军刀,轻轻一划,所有 undefined 的烦恼都烟消云散。

一、传统防守:&& 的"人肉护盾"

在过去,为了安全地访问深层嵌套的属性,我们不得不写这样的代码:

javascript 复制代码
const firstName = user && user.profile && user.profile.name && user.profile.name.firstName;

如果中间任何一环是 null 或 undefined,整个表达式短路返回 undefined,不会报错。但这写法,读起来像在爬楼梯,每层都要确认一下。

更别提调用可能存在的方法:

javascript 复制代码
const result = api && api.getData && api.getData();

万一 api.getData 不是函数?又得加判断。

二、可选链:.?. 的优雅空降

可选链操作符 ?. 允许你读取位于连接链深处的属性,而无需显式验证每一环是否有效。如果引用是 null 或 undefined,表达式短路返回 undefined。

javascript 复制代码
const firstName = user?.profile?.name?.firstName;

就这么简单!如果 user、profile、name 任何一个不存在,整个表达式返回 undefined,而不是报错。

2.1 函数调用可选链

javascript 复制代码
const result = api?.getData?.();

如果 api 是 null/undefined,或者 api.getData 不是函数,都返回 undefined,不会抛错。

2.2 数组元素可选链

javascript 复制代码
const firstItem = arr?.[0];

如果 arr 不是数组或者是 null/undefined,返回 undefined。

2.3 与空值合并搭配使用

javascript 复制代码
const firstName = user?.profile?.name?.firstName ?? '匿名';

如果最终结果是 undefined 或 null,就换成默认值。完美!

三、实战对比:代码简洁度暴增

场景1:读取深层 API 响应

javascript 复制代码
// 旧写法
const city = response && response.data && response.data.user && response.data.user.address && response.data.user.address.city;

// 新写法
const city = response?.data?.user?.address?.city;

场景2:调用可选回调

javascript 复制代码
// 旧写法
if (onSuccess && typeof onSuccess === 'function') {
  onSuccess(data);
}

// 新写法
onSuccess?.(data);

场景3:动态属性名

javascript 复制代码
const value = obj?.[key];

四、注意事项:别滥用

  • ?. 只检查左侧是否为 null 或 undefined ,不检查 false、0、'' 等假值。如果你需要过滤假值,用 || 或 ??。
  • 不能用于赋值 :obj?.prop = value 是语法错误。
  • 短路效应 :一旦遇到 null/undefined,右侧整个链停止求值,包括函数调用。
  • 性能 :现代浏览器对 ?. 优化很好,放心用。

五、兼容性与降级

可选链是 ES2020 特性,现代浏览器都支持(Chrome 80+、Firefox 74+、Safari 13.1+)。如果需要兼容旧浏览器,可以用 Babel 插件 @babel/plugin-proposal-optional-chaining 转译。

六、总结:告别防御性编程噩梦

可选链操作符让 JavaScript 代码变得更加简洁、安全、可读。你不再需要写一长串 && 来保护每一层属性访问,也不用担心 Cannot read property of undefined 半夜叫醒你。

记住:用 ?. 代替 && 链,用 ?? 提供默认值。这两个好基友,能让你的代码年轻十岁。


每日一问 :你曾经因为忘记检查深层属性,导致过线上报错吗?或者写过最长的 && 链有多长?评论区晒出你的"防御塔"代码,让大家开开眼!

相关推荐
SGAMERrain几秒前
# Nuxt 4 + MediaPipe:如何在浏览器中实现本地 AI 人脸分析?
前端
github_is_geeksKai1 小时前
浏览器端文件处理的边界:PDF 面单、GPX 隐私与 EPUB 修复
前端
李纲明1 小时前
微信小程序 getSystemInfo 提示已废弃、屏幕高度算错胶囊还对不齐?getWindowInfo 和 getDeviceInfo 怎么接才稳
javascript·微信小程序·小程序·小程序开发·devdiy
deli0072 小时前
从一句反馈到一次升级:Mystudy 的自进化实践
前端
FungLeo2 小时前
成为全栈·Vue 管理后台篇·用 fetch 建一层可控的请求内核
前端·javascript·vue.js·http·fetch·formdata·接口封装
用户84298142418103 小时前
ByteJS,让重要的 JavaScript 以字节码运行。
javascript
FungLeo4 小时前
成为全栈·Vue 管理后台篇·Vue Router如何守住多角色后台边界
前端·javascript·vue.js·rbac·vue router·路由守卫·前端权限
FungLeo4 小时前
成为全栈·Vue 管理后台篇·分页只显示第一页:从接口total 定位到前端修复
前端·vue.js·状态模式·分页·naive ui·服务端分页·前端问题排查
ZhengEnCi5 小时前
苹果滑动为什么有「肉感」:橡皮筋越界阻尼与弹簧动画的物理原理
前端
Moment5 小时前
不会后期的我,发现了一个开源胶片神器😍😍😍
前端·后端·开源