1. 空值合并 ??
只针对 null
和 undefined
,对 ''
、 0
、 NaN
及 false
无效,所以这同||
是有区别的,写法是 ??
连接
- obj?.prop // 对象属性
- obj?.[expr] // 同上
- func?.(…args) // 函数或对象方法的调用
// 普通对象
const user = { age 0 }
let age = user.age ?? 50 // value is 0
let ageWrong = user.age || 50 // value is 50
// 函数
funtion register(a, b) {
console.log(a, b);
}
this.register?.(1, 2); // register函数存在,则执行此函数,并且可传参
复制代码
仅当 age 为 undefined 或者 null 时才使用 50 这个值
2. 可选链 ?.
在对象属前面使用 ?.
连接会检查该属性是否为 null
或 undefined
,以避免代码崩溃。
const house = { owner: { name: 'Jim', pet: null }};
// 以前的写法
if(house && house.owner && house.owner.pet && house.owner.pet.type === 'dog'){
console.log('owner has a dog');
}
// 新特性的写法
if (house?.owner?.pet?.type === 'dog') {
console.log('owner has a dog');
}
复制代码
&&
、||
运算符一起使用时,需要用括号来表明优先级,要不会报错。
a && b ?? c // 错误
(a && b) ?? c // 正确
复制代码
3. Promise.allSettled
以前处理多个异步请求一并返回使用的是 Promise.all
但如果其他一个请求失败了就会报出异常,但使用 Promise.allSettled
则不一样,不管请求成功或失败都会把结果返回过来
const promises = [Promise.resolve(1), Promise.reject(2)];
const [result1, result2] = await Promise.allSettled(promises);
复制代码
即使其他 promise
被拒绝了,我们仍然可以在这里使用 result1
的值。
Promise.all
都成功,才会成功,有一个失败,就返回失败。
返回数组,每一个成员都是实例对应的结果。
Promise.allSettled
一旦结束,状态总是fulfilled,不会变成rejected。
返回数组,数组的每一个成员都是对象,每个对象都有status
属性,该属性的值只可能是字符串fulfilled
或字符串rejected
。fulfilled
时,对象有value
属性,rejected
时有reason
属性,对应两种状态的返回值.
Promise.race
其中一实例返回状态,p的状态就会发生改变,并且不会再变。
只要有返回值,立马停止其他请求。
4. matchAll
如果要用正则表达式查找所有的匹配项,可以用 match
来得到所有子字符串。但是,如果你既需要子字符串又需要索引,该怎么办?这时可以用 matchAll
并进行重复匹配。
const matches = 'Here are some numbers: 3 15 32'.matchAll(/\d+/g);
for (const match of matches) {
console.log(match);
}
// 输出:
// ["3", index: 22, input: "Here are some numbers: 3 15 32", groups: undefined]
// ["15", index: 24, input: "Here are some numbers: 3 15 32", groups: undefined]
// ["32", index: 27, input: "Here are some numbers: 3 15 32", groups: undefined]
复制代码
ES2020之前
let regex = /t(e)(st(\d?))/g;
let string = 'test1test2test3';
let matches = [];
let match;
while (match = regex.exec(string)) {
matches.push(match);
}
console.log(matches); // 返回正则表达式在当前字符串所有匹配(数组)
复制代码
可一次性取出所有匹配,但是返回的是一个遍历器(Iterator
),而非数组。可以用for of
循环取出。
相对于返回数组,返回遍历器的好处在于,如果遍历结果是一个很大的数组,那么遍历器比较节省资源。
遍历器转换成数组,也是比较方便,可以使用...
运算符和Array.from()
就可以了。
let regex = /t(e)(st(\d?))/g;
let string = 'test1test2test3';
[...string.matchAll(regex)];
// 或
Array.from(string.matchAll(regex));
复制代码
5. BigInt
在处理大于 9007199254740991 的数字时应该用 BigInt。 BigInt 在数字末尾用 n 表示。
9_007_199_254_740_991 + 2; // 9007199254740992
BigInt(9_007_199_254_740_991) + BigInt(2) // 9007199254740993n
复制代码
6. 动态导入
以前是先导入再使用,新特性可以动态导入使用了,因为 import()
会与模块一起返回一个 Promise
const utils = await import('utils');
复制代码
7. globalThis
如果你的代码需要在多个环境(例如浏览器和 Node
服务器)下运行,那么它们所使用全局对象名称并不一致。在浏览器中用的是 window
,Node
则用的是 global
,而 web worker
用的是 self
。现在,无论代码在哪种环境中运行,globalThis
都能够为你提供正确的全局对象。
if (typeof globalThis.alert === 'function'){
globalThis.alert('hello');
}
复制代码
8. 管道运算符 |>
有时也会遇到这个场景,一个参数,不断经过函数处理,结果又被当作参数传给下个函数
const result = foo(bar(baz('hello world')))
复制代码
管道给人的感觉就是一条流水线,从上到下,参数输入,结果输出,很简洁~
const result = 'hello world' |> baz |> bar |>foo
复制代码
再举个栗子:
const double = (n) => n * 2;
const increment = (n) => n + 1;
double(increment(double(double(5)))); // 42
//使用管道操作符
5 |> double |> double |> increment |> double; // 42
复制代码
想在项目中使用同样需要babel7,并使用 @babel/plugin-proposal-pipeline-operator
插件
"plugin": [
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "minimal"
}
]
]
复制代码
注意,在配置 .babelrc
时需要指定 proposal
参数,更多参数请了解
babeljs.io/docs/en/bab…
如果函数还需要别的参数,可以这么写:
const result = 'hello world' |> baz |> (str => baz(str, 'other args')) |> foo
复制代码
但是如此就看着不简洁了,所以有个备选方案:使用#代表上个结果值,即:
const result = 'hello world' |> baz |> baz(#, 'other args')) |> foo
复制代码
9. 私有变量
在变量前加 #
,可以定义私有变量,仅能在类内部使用
class Message {
#message = "Howdy"
greet() { console.log(this.#message) }
}
const greeting = new Message()
greeting.greet()
console.log(greeting.#message)
复制代码
如果本文对你有所帮助,感谢点一颗小心心,您的支持是我继续创作的动力!