【笔记】可选链式调用optional-chaining
Jun 25, 2019笔记前端jses6可选链式调用optional-chaining
- 2019.8 Stage 2 -> Stage 3
引导
当我们访问一个深层树形结构的对象时,我们总需要判断中间节点属性是否存在:1
let street = user.address && user.address.street;
或者在DOM操作获取值的时候也需要先判断节点是否存在:1
2let fooInput = document.querySelector('input[name=foo]');
let fooValue = fooInput ? fooInput.value : undefined;
虽然为了不报错,我们不得不加上这种判断,有时候甚至更加麻烦。
始终觉得这类操作很麻烦是不,这就是接下来 Optional chaining大放光彩的时刻
Optional chaining
optional chaining(可选练市调用)就是添加了?.
这么个操作符这么简单,它会先判断前面的值,如果是 null 或 undefined,就结束调用并返回 undefined。
Optional chaining是一个在2018.11月提交的方案,当前状态为stage 3(2019.8)。
Optional Chaining 的语法有三种使用场景:1
2
3obj?.prop // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call
有了optional chaining,上面的麻烦写法就可以简化成这样:1
2let street = user.address?.street
let fooValue = document.querySelector('input[name=foo]')?.value
再看babel给出的一个案例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const obj = {
foo: {
bar: {
baz: 42,
},
},
};
const baz = obj?.foo?.bar?.baz; // 42
const safe = obj?.qux?.baz; // undefined
// Optional chaining and normal chaining can be intermixed
obj?.foo.bar?.baz; // Only access `foo` if `obj` exists, and `baz` if
// `bar` exists
// Example usage with bracket notation:
obj?.['foo']?.bar?.baz // 42
这么多层的判断都免了,很爽。
Optional chaining 也可以用在方法上,如:1
iterator.return?.()
或者试图调用某些未被实现的方法:1
2
3
4if (myForm.checkValidity?.() === false) { // skip the test in older web browsers
// form validation fails
return;
}
优先级顺序
既然?.
作为运算符,那么它的运算优先级如何?可通过一下几个例子大致了解:1
2(a?.b).c // -> (a == null ? undefined : a.b).c
a?.b.c // -> a == null ? undefined : a.b.c
Optional delete
1 | delete a?.b // -> a == null ? true : delete a.b |
这样不论 b 是否存在,得到的都是 b 删除成功的信号(返回值 true)。
项目中使用
如此灵活好用的功能,在项目中该如何运用呢?
babel插件
首先babel给出了插件:babel/plugin-proposal-optional-chaining
安装:1
npm install --save-dev @babel/plugin-proposal-optional-chaining
配置(如.babelrc
文件)1
2
3{
"plugins": ["@babel/plugin-proposal-optional-chaining"]
}
更多babel配置请见参考资料中其babel插件。
TypeScript
TypeScript中并无此操作符或草案,但TypeScript给出了更直接的方案,并也有此插件ts-optchain
如1
2
3import { oc } from 'ts-optchain';
const obj: T = { /* ... */ };
const value = oc(obj).propA.propB.propC(defaultValue);
将被转换成:1
2
3
4const value =
(obj != null && obj.propA != null && obj.propA.propB != null && obj.propA.propB.propC != null)
? obj.propA.propB.propC
: defaultValue;
*拓展
配合另一个新特性 Nullish Coalescing 做默认值处理非常方便,它添加了??
这个操作符,如1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false
Author
My name is Micheal Wayne and this is my blog.
I am a front-end software engineer.
Contact: michealwayne@163.com