📖
blog
  • README
  • JavaScript
    • 元素的宽高位置信息梳理
    • dom-align 源码浅析
    • Event Loop
    • 函数实参为对象时的陷阱
    • export 与 utils 方法书写规范
    • 手写 Promise 及相关代码理解
    • call,apply,bind 等函数的模拟实现
    • JavaScript继承
    • JavaScript 数据类型与类型判断
    • for..of 和 for..in 的区别
    • 写给自己看的 next 函数
    • JS 可选链与双问号
    • mouseenter 与 mouseover 事件的区别
    • Immutable相关知识
  • CSS
    • 不简单的 z-index
    • 两列布局,三列布局
    • CSS 居中方案整理
    • CSS 像素,设备像素,2倍图梳理
    • iconfont 的使用
  • Node JS
    • 实现简易的 express
  • React 核心知识点整理
    • 高阶组件
    • React 事件处理
    • React Hooks
    • React Context
  • React 状态管理
    • Redux 基础概念
    • Redux 中间件和异步操作
    • Redux Saga
    • Redux 只能有一个 store 对象嘛
  • React 开发实践
    • Ant Design Menu 组件的使用与深入
    • 讲讲吸顶效果与 react sticky
    • 基于 express,搭建 react 的开发环境
    • 通过 antd input 组件分析受控与非受控组件
    • DebounceClick 组件
    • react component Align 组件分析
    • React Portal 之事件冒泡
    • React Transition Group 源码浅析
    • React.cloneElement 父组件向子组件注入 props
    • 一次 Align 组件的问题记录
    • 如何知道子组件的类型
    • React Router 源码简单分析
    • React Redux 源码简单分析
  • Vue.js
    • Vue.js 概览
    • scoped 样式中的 deep
  • TypeScript 语法
    • 基础类型
    • 变量声明
    • 接口
    • 类
    • 函数
    • 泛型
    • 枚举
    • 类型推论
    • 类型兼容性
    • 高级类型
    • Symbol
    • 迭代器和生成器
    • 模块
    • 命名空间
    • JSX
  • 玩转 webpack
    • 第一章: webpack 与构建发展简史
    • 第二章:webpack基础用法
    • 第三章:webpack进阶用法
    • 第四章:编写可维护的 webpack 构建配置
    • 第五章:webpack构建速度和体积优化策略
    • 第六章:通过源代码掌握webpack打包原理
    • 第七章:编写Loader和插件
  • webpack 实践
    • 如何配置 output.library
  • 测试
    • 初识代码测试
    • Jest 中 如何测试 setTimeout
    • Jest Enzyme React 测试实践记录
  • WEB 开发,过往工作沉淀
    • Web安全(DVWA)
    • 内存泄露与事件移除的必要性
    • url to pdf api 与 服务部署踩坑记录
    • 前端调试指南
    • Markdown 转 email
    • github travis ci 自动部署
    • 浏览器缓存知识梳理
    • WEB 系统登录相关知识梳理
    • 将-Axios-请求参数和返回值进行格式化
    • source-map与源码调试
    • HTTPS
    • 使用 rollup 打造自己的 npm 包 (全流程)
    • father-build 是如何工作的
  • 书籍
    • 图解 HTTP 协议
    • 编写可维护的 JavaScript
    • 鸟哥的 Linux 私房菜
    • JavaScript Promise迷你书
  • Linux
    • vimtutor
    • CURL 使用指南
  • Nginx
    • 一次 nginx 分享
  • Git
    • Git Commit Message 须知
    • .gitignore 模板
    • git tag标签
  • 摄影
    • 摄影基础知识
    • 手机摄影从小白到大师
  • 翻译
    • log4js
    • log4js-node
    • 介绍GitLab上的CI/CD
    • 为GitLab Pages创建并调整GitLab CI/CD
    • 关于 rel=noopener
    • AngularJS 团队 Git 提交信息约定
    • JSON Schema
  • Lifehack
    • 20 个 Google 搜索 Tips 来高效使用 Google
    • 37 个高级 Google 搜索 Tips
Powered by GitBook
On this page
  • 前言
  • 1. 可选链(Optional chaining) ?.
  • 2. 双问号(Nullish coalescing operator) ??
  • 3. 可选链与双问号
  • 参考资料

Was this helpful?

  1. JavaScript

JS 可选链与双问号

为了测试新语法,可以打开参考资料中的 MDN 链接,其中有在线编辑器,或者使用 Chrome console

前言

公司的代码中已经开始有 ?? 和 ?. 了,刚看到这些代码有点摸不着头脑,看完 MDN 也就了解个大概。

担心细枝末节被我忽略了,得空来整理一下

1. 可选链(Optional chaining) ?.

以前我们可能会写这样的代码:

const a = {
    b: {
        c: {
            d: [1]
        }
    }
}

const data = (a && a.b && a.b.c && a.b.c.d) || []

即为了确保不会报 cant read property from property, 我们需要添加很长的判断条件

有了,可选链之后,你可以这样:

示例一:

a.e.f  // 报错,a.e 为 undefined,取 undefined.f 会报错

a.e?.f // undefined, 即,使用可选链之后,不会报错

a?.e.f
// 报错,即,a?.e 只能保证即使 a 为 undefined,a.e 也不会报错
// 但是不能阻止 a.e.f 报错

// 但是
console.log(a?.e.f.d.g)   // 会报错,a?.e 为 undefined, f 不是 undefined 的属性
console.log(a.e.f?.d.g)   // 会报错,a.e 为 undefined, f 不是 undefined 的属性
console.log(a.e?.f.d.g)  // 这样居然不会报错???为什么


// 针对以上会报错的两种情况,可以使用多个可选链叠加一起使用
console.log(a?.e?.f?.d?.g)   // 不会报错

示例二:

const a = null;
a.b;  // 报错,b 不是 null 的属性

a?.b  // 不会报错,打印 undefined

a?.b.c.d.e.f  // 打印 undefined, 不会报错, 为什么 ???

示例三, 可选链与函数调用:

语法 func?.(args)

const a = {
    b: {
        c: {
            d: [1]
        }
    }
}
console.log(a.e?.())  // 不会报错
console.log(a.e?.b())  // 同样不会报错


const a = {
    e: {
        c: {
            d: [1]
        }
    }
}
console.log(a.e?.())  // 会报错,a.e 不是函数


就是说,通过可选链,如果 a.e 为 null 或者 undefined,调用a.e?.() 不会报错。

但是,如果存在 a.e, 但是 a.e 不是函数,那么还是会正常报错

总结 可选链操作符使得:

  • 当对象为 null 或者 undefined 时,读取对象的属性不会报错。

  • 当函数为 null 或者 undefined 时, 调用该函数不会报错

  • 如果遇到连续的属性访问时,可以使用多个可选链(坏处可能是被 babel 编译之后,代码量变多)

2. 双问号(Nullish coalescing operator) ??

left ?? right

当 left 为 null 或者 undefined 时,返回右边的值.

注意: 和 || 不一样的是,如果 left 为 '' 或者 0 或者 false, ?? 依然会返回 left 的值:

const foo = null ?? 'default string';
console.log(foo);   // 返回右边的值 default string

const foo = null || 'default string';
console.log(foo);   // 返回右边的值 default string

// 遇到 false,0,'', NaN 时不一样
const baz = 0 ?? 42;
console.log(baz);   // 返回左边的值,0

const baz = 0 || 42;
console.log(baz);   // 返回右边的值,42

同样,它也有短路操作

function A() { console.log('A was called'); return null;}
function B() { console.log('B was called');}

console.log( A() ?? B() );
// A 函数执行,返回 undefined,
// ?? 认为 undefined 是 "false" 值,此时会继续计算 B 函数
// 最终返回 undefined(B 函数没有返回值,则默认为 undefined)

// 短路
function A() { console.log('A was called'); return false;}
function B() { console.log('B was called');}

console.log( A() ?? B() );
// A 函数执行,返回 false,
// ?? 认为 false 是 "true" 值,不再计算 C 函数, 最终返回 false

3. 可选链与双问号

可选链允许使用 undefined?.xxx() 而不报错,当然不报错是一回事,它的返回结果还是 undefined.

因此,这种时候可以再配合双问号来设置默认值:

undefined?.xxx()  ?? '123'  // 返回 123

参考资料

Previous写给自己看的 next 函数Nextmouseenter 与 mouseover 事件的区别

Last updated 4 years ago

Was this helpful?

JS 新语法「可选链」「双问号」已进入 Stage 3
MDN 可选链
MDN 双问号