?.
(Optional Chaining) 和 ??
(Nullish Coalescing Operator)
船新版本的JavaScript(一):大扎好,我系Iron。Babel 7,介四里没有挽过的船新版本,挤需体验三番钟,里造会干我一样,爱上这门语言
?.
可选链调用(Optional Chaining)
背景
我们经常会遇到这样的情况,我们要去读取一个嵌套的对象中的某个深层的值,但我们必须检验我们访问的“路径”的每个节点是否为null
或undefined
,这种情况下我们一般是这么来的
const street = user.address && user.address.street;
如果是foo.bar.biz.bah这样的路径,那么我们得这么写
const bah = foo && foo.bar && foo.bar.biz && foo.bar.biz.bah
这个提案出现就是为了避免使用 &&
或者||
并不断重复“访问路径"中的属性名(就是上面不断出现的foo
, bar
, biz
)
语法
// 带空指针检查地取静态属性
a?.b
// 等效于
a == null ? undefined : a.b
// NOTE: null == undefined 会返回ture
// 取动态的属性
a?.[x]
// 将被转化为
a == null ? undefined : a[x]
// 检查一个函数的引用是否为空,非空则调用它,否则直接返回undefined
// 当然这也可能会抛出异常,显然会出现func既不是函数也不是null也不是undefind的情况
func?.()
//
func == null ? undefined : func()
短路
?.
运算符具有短路的特性。?.
左边的值为null
或undefined
,那么它右边的表达式将不会执行
a?.[++x]
// 等效于
a == null ? undefined : a[++x]
// 当a为null或者undefined时++x不会执行,x不变
当短路发生时,不仅短路当前?.
的右值,?.
之后的所有表达式都会被短路掉
a?.b.c(++x).d
// 后面的`b.c(++x).d`被短路,++x不会被执行,上面这段代码等效于
a == null ? undefined : a.b.c(++x).d
边界:括号
括号会为?.
的短路行为定一个边界,括号外的调用将不会被短路
(a?.b).c
// `.c`在a为null或者undefined的时候也会被调用,因此可能会引发空指针异常
(a == null ? undefined : a.b).c
delete
delete a?.b
// 我们会得到下面的
a == null ? undefined : delete a.b
// 不过delete删掉一个null或者undefined也不会报错
??
(空值合并)(Nullish Coalescing Operator)
背景
首先,我们先下个定义,一个Nullish
的值,即这个值为null
或undefined
,一个falsy
的值,即在Boolean上下文中可被认定为false
的值,他们是(''
, false
, 0
, null
, undefined
, NaN
, document.all
)
当我们用上面所说的?.
(optional chaining operator)运算符去读取属性有时会返回null
或undefined
,这个时候我们可能需要一个默认值
举个例子
假设我们有这么一个对象
const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
似乎我们可以用||
运算符给?.
(optional training operator)的结果指定一个默认值
const undefinedValue = response.settings?.undefinedValue || 'some other default'; // 结果是'some other result'
const nullValue = response.settings?.nullValue || 'some other default'; // 结果也是'some other result'
上面两种情况可以按照我们想象的方式工作
但下面三种情况,?.
运算符的结果为falsy
但不为nullish
,但最后还是可能返回||
的右值
const headerText = response.settings?.headerText || 'Hello, world!'; // 当`||`左值为''(空字符串)时,表达式结果:'Hello, world'
const animationDuration = response.settings?.animationDuration || 300; // 左值为0时,表达式结果: 300
const showSplashScreen = response.settings?.showSplashScreen || true; // 左值为false时,表达式结果为true
因此使用||
给?.
的结果指定默认值时,当左值为falsy
且不是nullish
,||
运算依旧会返回右边的默认值,这与我们所希望的,只有当?.
结果为nullish
时才返回一个默认值的意愿是相左的。
当然我们可以直接用三目运算符避免这种情况。??
运算符的出现是为了更好地处理左值为非nullish
但为falsy
时需要返回左值的情况
语法
这个运算符的语法非常简单
以上面的例子为例,??
运算符的左值为null或undefined时返回右值,否则返回左值
const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // 'some other default'
// 下面三个左值为非null且非undefined,返回左值
const headerText = response.settings?.headerText ?? 'Hello, world!'; // : ''
const animationDuration = response.settings?.animationDuration ?? 300; // 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // false
?.
和??
如何在代码中用上babel已经实现了这两个语法,他们可以用babel7的插件来编译到兼容的语法上
安装
npm install --save-dev @babel/plugin-proposal-optional-chaining
npm install --save-dev @babel/plugin-proposal-nullish-coalescing-operator
# 用yarn装也无所谓
配置
在.babelrc里加上这么两句
{
"plugins": ["@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-optional-chaining"]
}
如果有webpack的话需要在webpack 中babel-loader
的options中加上
{
loader: 'babel-loader',
options: {
plugins: [
require('@babel/plugin-proposal-nullish-coalescing-operator'),
require('@babel/plugin-proposal-optional-chaining')
]
}
}
使用
最后在命令行里敲webpack
或者babel
就行了
参考资料
TC39 optional chaining proposal
TC39 nullish coalescing operator proposal