你到现在还只知道ES2015(ES6)?ES2020都出来啦!马上撸起来~
动态import()
实际上,动态import()很早就提出来了,并且有实验的版本,但是需要通过babel来编译成浏览器支持的语法。现在,浏览器已经原生支持动态import()啦!
静态import的用法
静态import在代码执行前就”绑定“了当前的作用域,并且只能用在文件的最顶层。
举个栗子,有如下模块./utils.mjs:
export default () => {
console.log('Hi from the default export!')
}
export const doStuff = () => {
console.log('Doing stuff…')
}
以下代码演示如何静态引入utils.mjs模块:
<script type='module'>
import * as module from './utils.mjs'
module.default()
module.doStuff()
</script>
静态import使得诸如静态分析、构建工具、tree-shaking等应用场景可行。但是,并不支持以下场景:
- 按需引入模块;
- 在运行时计算模块的标识符。
动态import()的用法
动态import()引入了一种以函数形式来适应静态import所不支持的应用场景。import(moduleSpecifier)返回一个promise对象。
以下代码演示如何动态引入utils.mjs模块:
<script type="module">
const moduleSpecifier = './utils.mjs'
import(moduleSpecifier)
.then((module) => {
module.default()
module.doStuff()
})
</script>
由于import()返回一个promise对象,所以可以使用async/await来代替then形式的回调方式:
<script type="module">
(async () => {
const moduleSpecifier = './utils.mjs'
const module = await import(moduleSpecifier)
module.default()
module.doStuff()
})()
</script>
BigInt:JS中任意精度的整数类型
在JS中,Number表示双精度浮点数,这意味着Number具有有限的精度。从Number.MIN_SAFE_INTEGER到Number.MAX_SAFE_INTEGER。正如JS开发者皆知的0.10 + 0.20 !== 0.30。
BigInt是JS中一种新的原始数字类型,它可以表示任意精度的整数。该功能在Chrome 67开始引入。
如何创建一个BigInt
只要添加一个n后缀到任意整型,就可以创建一个BigInt。比如,123变成123n,全局的BigInt(number)函数就会将Number转换成一个BigInt。
const max = Number.MAX_SAFE_INTEGER
console.log(max) // 9007199254740991
console.log(max + 1) // 9007199254740992
console.log(max + 2) // 9007199254740992,wrong answer!
console.log(BigInt(max) + 2n) // 9007199254740993n,correct!
1234567890123456789 * 123 // 151851850485185200000,wrong answer!
1234567890123456789n * 123n // 151851850485185185047n,correct!
BigInt:一种新的原始类型
typeof 123 // 'number'
typeof 123n // 'bigint'
42n === BigInt(42) // true
42n == 42 // true
42n === 42 // false
if (0n) {
console.log('if')
} else {
console.log('else') // 'else'
}
BigInt支持的运算符
BigInt支持绝大部分场景的运算符,包括二元运算符+、-、*、**;/、%,位运算符|、&、<<、>>、^。
(7 + 6 - 5) * 4 ** 3 / 2 % 3 // 1
(7n + 6n - 5n) * 4n ** 3n / 2n % 3n // 1n
-42n // 表示负数
+42n // 报错,一元运算符+只能用于Number类型
**注意:JS不允许混用BigInt和Number,因为这样会丢失精度。**比如:
BigInt(Number.MAX_SAFE_INTEGER) + 2.5 // 报错
但是,有个例外,BigInt和Number可以用于比较,因为比较并不会丢失精度:
123 < 124n // true
BigInt API
- BigInt.asIntN(width, value):将一个BigInt转换成一个width位的有符号整数。
- BigInt.asUintN(width, value):将一个BigInt转换成一个width位的无符号整数.
- BigInt64Array(length)
- BigUint64Array(length)
BigInt(123) // 123n
BigInt(1.5) // RangeError
BigInt('1.5') // SyntaxError
// Highest possible BigInt value that can be represented as a signed 64-bit integer.
const max = 2n ** (64n - 1n) - 1n
BigInt.asIntN(64, max) // 9223372036854775807n
BigInt.asIntN(64, max + 1n) // -9223372036854775808n,negative because of overflow
const view = new BigInt64Array(4) // [0n, 0n, 0n, 0n]
view.length // 4
view[0] // 0n
view[0] = 42n
view[0] // 42n
Module namespace exports
在JS模块中,以下语法已经被支持:
import * as utils from './utils.mjs'
然而,没有对应的export语法。但现在有了:
export * as utils from './utils.mjs'
// 该语句相当于:
import * as utils from './utils.mjs'
export { utils }
String.prototype.matchAll
- matchAll尤其适用于具有捕获组(capture groups)的正则表达式。
- 注意:调用matchAll必须使用一个全局搜索的正则,否则会报错。
const string = 'Favorite GitHub repos: tc39/ecma262 v8/v8.dev'
const regex = /\b(?<owner>[a-z0-9]+)\/(?<repo>[a-z0-9\.]+)\b/g
for (const match of string.matchAll(regex)) {
console.log(`${match[0]} at ${match.index} with '${match.input}'`)
console.log(`→ owner: ${match.groups.owner}`)
console.log(`→ repo: ${match.groups.repo}`)
}
// 输出:
// tc39/ecma262 at 23 with 'Favorite GitHub repos: tc39/ecma262 v8/v8.dev'
// → owner: tc39
// → repo: ecma262
// v8/v8.dev at 36 with 'Favorite GitHub repos: tc39/ecma262 v8/v8.dev'
// → owner: v8
// → repo: v8.dev
Promise Combinators
- Promise.all:只要有任意一个promise状态变为rejected,就会”短路“。ES2015引入。
- Promise.race:只要有任意一个promise完成(fulfilled/rejected),就会”短路“。ES2015引入。
- Promise.allSettled:等待所以promise完成(fulfilled/rejected)才返回,不会”短路“。ES2020引入。
- Promise.any:只要有任意一个promise状态变为fulfilled,就会”短路“。还处于proposal中。
Promise.all
const promises = [
fetch('/component-a.css'),
fetch('/component-b.css'),
fetch('/component-c.css'),
]
try {
const styleResponses = await Promise.all(promises)
enableStyles(styleResponses)
renderNewUi()
} catch (reason) {
displayError(reason)
}
Promise.race
try {
const result = await Promise.race([
performHeavyComputation(),
rejectAfterTimeout(2000),
])
renderResult(result)
} catch (error) {
renderError(error)
}
Promise.allSettled
// Imagine some of these requests fail, and some succeed.
const promises = [
fetch('/api-call-1'),
fetch('/api-call-2'),
fetch('/api-call-3'),
]
await Promise.allSettled(promises)
// All API calls have finished (either failed or succeeded).
removeLoadingIndicator()
Promise.any
const promises = [
fetch('/endpoint-a').then(() => 'a'),
fetch('/endpoint-b').then(() => 'b'),
fetch('/endpoint-c').then(() => 'c'),
]
try {
const first = await Promise.any(promises)
// Any of the promises was fulfilled.
console.log(first)
} catch (error) {
// All of the promises were rejected.
console.log(error)
}
globalThis
在之前,我们需要做很多判断来获取全局this,比如,浏览器中的window,node环境中的global。现在,globalThis关键字引入了一种统一的机制来访问任意JS环境中的全局this值。Chrome 71+支持。
const theGlobalThis = globalThis
Optional chaining
Optional chaining在Chrome 80+开始支持。
在optional chaining出现之前
对于对象深层次的属性访问,很容易出现引用错误:
// 很可能会出错
const nameLength = db.user.name.length;
// 不会出错,但不易读
let nameLength
if (db && db.user && db.user.name) {
nameLength = db.user.name.length
}
optional chaining的用法
// 仍然会检查错误,并且更加易读
const nameLength = db?.user?.name?.length
// 调用optional方法:
const adminOption = db?.user?.validateAdminAndGetPrefs?.().option
// 访问动态的属性名:
const optionName = 'optional setting'
const optionLength = db?.user?.preferences?.[optionName].length
// optional数组下标,若数组为null/undefined,返回undefined:
const userIndex = 42
const userName = usersArray?.[userIndex].name
optional chaining的特性
- Short-circuiting:若optional chaining提前返回了,后面的语句则不会再执行。
- Stacking:属性访问中可以有多个optional chaining操作符。
- Optional deletion:delete操作符可以和optional chaining组合使用。
// age is incremented only if db and user are defined.
db?.user?.grow(++age)
// An optional chain may be followed by another optional chain.
const firstNameLength = db.users?.[42]?.names.first.length
// db.user is deleted only if db is defined.
delete db?.user
Nullish coalescing
Chrome 80+开始支持Nullish coalescing——??。
false ?? true // => false
0 ?? 1 // => 0
'' ?? 'default' // => ''
null ?? [] // => []
undefined ?? [] // => []
const link = document.querySelector('link') ?? document.createElement('link')
const link = obj.deep?.container.link ?? document.createElement('link')
本文章来自我的微信公众号:前端酱的日常
欢迎关注我的微信公众号!持续更新中!

本文使用 mdnice 排版