发布时间:2020年6月 ES11 是一个重要版本,新增了空值合并、可选链、BigInt、动态导入等特性。
1. 可选链运算符(Optional Chaining)?.
安全地访问深层嵌套的属性,遇到 null 或 undefined 时短路返回 undefined,不报错。
基本用法
let user = {
name: '张三',
address: {
city: '北京',
street: '长安街'
}
};
// 旧写法
let city = user && user.address && user.address.city;
// 新写法
let city = user?.address?.city; // '北京'
let zip = user?.address?.zip; // undefined(不会报错)
let phone = user?.contact?.phone; // undefined
可选链调用方法
let obj = {
method() { return 42; }
};
obj.method?.(); // 42
obj.otherMethod?.(); // undefined(不会报错)
可选链访问数组元素
let arr = null;
let item = arr?.[0]; // undefined
let item2 = arr?.[0]?.name; // undefined
注意事项
// 可选链不能用于赋值
obj?.name = '李四'; // SyntaxError
// 如果前面的值为 null/undefined,后面的表达式不会执行
let a = null;
let b = a?.foo.bar.baz(); // undefined,foo.bar.baz() 不会执行
实际应用
// 从 API 返回的数据中安全取值
let data = response?.data?.list?.[0]?.name;
// DOM 操作
let value = document.querySelector('#input')?.value;
// React/Vue 中
let userName = this.props?.user?.name ?? '匿名用户';
2. 空值合并运算符(Nullish Coalescing)??
只在值为 null 或 undefined 时使用默认值(|| 会在值为 0、''、false 时也触发)。
基本用法
// || 的问题:0、''、false 都会被当作假值
let count = 0;
console.log(count || 10); // 10(错误!0 被当成假值)
console.log(count ?? 10); // 0(正确!只有 null/undefined 才用默认值)
let name = '';
console.log(name || '匿名'); // '匿名'(错误!空字符串被覆盖)
console.log(name ?? '匿名'); // ''(正确!空字符串是有效值)
与 || 的对比
0 ?? 100; // 0
0 || 100; // 100
'' ?? 'default'; // ''
'' || 'default'; // 'default'
false ?? true; // false
false || true; // true
null ?? 'fallback'; // 'fallback'
null || 'fallback'; // 'fallback'
undefined ?? 'x'; // 'x'
undefined || 'x'; // 'x'
实际应用
// 设置默认值
let port = config.port ?? 3000;
let host = config.host ?? 'localhost';
let debug = config.debug ?? false;
// 与可选链组合使用
let name = user?.profile?.name ?? '匿名用户';
let count = list?.length ?? 0;
注意:不能与 || 和 && 混用
// 语法错误
null ?? 'default' || 'other'; // SyntaxError
// 需要加括号
(null ?? 'default') || 'other'; // 'default'
3. BigInt(大整数)
表示任意精度的整数,突破 Number.MAX_SAFE_INTEGER(2^53 - 1)的限制。
创建 BigInt
// 方式1:数字后加 n
let big1 = 9007199254740993n;
// 方式2:BigInt() 函数
let big2 = BigInt(9007199254740993);
let big3 = BigInt('9007199254740993');
解决精度问题
// Number 的精度限制
9007199254740992 === 9007199254740993; // true(精度丢失!)
// BigInt 没有精度限制
9007199254740992n !== 9007199254740993n; // true
运算
let a = 12345678901234567890n;
let b = 98765432109876543210n;
a + b; // 111111111011111111100n
a - b; // -86419753208641975320n
a * b; // 1219326311370217952237463801111263526900n
a / b; // 0n(BigInt 除法向下取整)
a % b; // 12345678901234567890n
// 比较运算
10n > 5; // true
10n === 10; // false(类型不同)
10n == 10; // true(宽松相等)
注意事项
// BigInt 不能与 Number 混合运算
10n + 5; // TypeError
// 需要先转换
Number(10n) + 5; // 15
BigInt(5) + 10n; // 15n
// 不能用 Math 方法
Math.max(1n, 2n); // TypeError
// JSON 不支持 BigInt
JSON.stringify({ a: 1n }); // TypeError
4. Promise.allSettled()
等待所有 Promise 完成(无论成功或失败),返回每个 Promise 的结果:
基本用法
let p1 = Promise.resolve('成功1');
let p2 = Promise.reject('失败');
let p3 = Promise.resolve('成功2');
Promise.allSettled([p1, p2, p3]).then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
// 成功: 成功1
// 失败: 失败
// 成功: 成功2
与 Promise.all 的区别
// Promise.all:任一失败就整体失败
Promise.all([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.log('有失败的:', err));
// 输出:有失败的: 失败
// Promise.allSettled:全部完成后才返回,包含每个结果
Promise.allSettled([p1, p2, p3])
.then(res => console.log(res));
// [
// { status: 'fulfilled', value: '成功1' },
// { status: 'rejected', reason: '失败' },
// { status: 'fulfilled', value: '成功2' }
// ]
实际应用
// 批量请求,关心所有结果
async function fetchAll(urls) {
let results = await Promise.allSettled(
urls.map(url => fetch(url).then(r => r.json()))
);
let succeeded = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
let failed = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
console.log(`成功: ${succeeded.length}, 失败: ${failed.length}`);
return { succeeded, failed };
}
5. 动态导入 import()
运行时按需加载模块,返回 Promise:
基本用法
// 静态导入:编译时加载,必须写在顶部
import { module } from './module.js';
// 动态导入:运行时按需加载
let module = await import('./module.js');
按需加载
// 点击按钮时才加载
button.addEventListener('click', async () => {
let { Chart } = await import('./chart.js');
new Chart(canvas, config);
});
条件加载
async function loadPolyfill() {
if (!window.Promise) {
await import('promise-polyfill');
}
}
路由懒加载
// React 路由懒加载
const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
注意
- 动态导入返回模块的命名空间对象
- 可以在普通脚本中使用(不限于模块脚本)
6. globalThis
统一的全局对象,在不同环境下指向正确的全局对象:
// 不同环境的全局对象不同:
// 浏览器中:window
// Web Worker 中:self
// Node.js 中:global
// ES11 提供统一的 globalThis
console.log(globalThis); // 浏览器中指向 window
实际应用
// 兼容写法(旧)
let globalObj = typeof window !== 'undefined' ? window
: typeof global !== 'undefined' ? global
: typeof self !== 'undefined' ? self : {};
// ES11 简化
let globalObj = globalThis;
7. String.prototype.matchAll()
返回字符串中所有匹配正则表达式的迭代器:
基本用法
let str = 'test1test2test3';
let matches = str.matchAll(/t(e)(st(\d?))/g);
for (let match of matches) {
console.log(match);
}
// ['test1', 'e', 'st1', '1', ...]
// ['test2', 'e', 'st2', '2', ...]
// ['test3', 'e', 'st3', '3', ...]
与 match 的区别
// match 带 g 标志时,只返回匹配的字符串
'test1test2'.match(/t(e)st(\d)/g);
// ['test1', 'test2']
// matchAll 返回完整的匹配信息(包括捕获组)
[...'test1test2'.matchAll(/t(e)st(\d)/g)];
// [
// ['test1', 'e', '1', ...],
// ['test2', 'e', '2', ...]
// ]
注意
matchAll要求正则必须有g标志- 返回的是迭代器,不是数组(可用
...或Array.from()转换)
8. for...in 标准化枚举顺序
ES11 进一步明确了 for...in 遍历对象字符串键时的顺序:
- 整数索引形式的键(按数值升序)
- 其他字符串键(按创建顺序)
注意: for...in 不会遍历 Symbol 键。
let obj = {};
obj[2] = 'b';
obj[0] = 'a';
obj[1] = 'c';
obj['name'] = '张三';
obj['age'] = 18;
obj[Symbol('id')] = 1;
for (let key in obj) {
console.log(key);
}
// 输出顺序:'0', '1', '2', 'name', 'age'
// Symbol('id') 不会被 for...in 遍历到
总结
| 特性 | 说明 | 重要性 |
|---|---|---|
?. 可选链 | 安全访问深层属性 | ⭐⭐⭐⭐⭐ |
?? 空值合并 | 更精确的默认值设置 | ⭐⭐⭐⭐⭐ |
BigInt | 任意精度大整数 | ⭐⭐⭐⭐ |
Promise.allSettled() | 获取所有 Promise 结果 | ⭐⭐⭐⭐ |
import() 动态导入 | 按需加载模块 | ⭐⭐⭐⭐ |
globalThis | 统一全局对象 | ⭐⭐⭐ |
String.matchAll() | 获取所有正则匹配 | ⭐⭐⭐ |
for...in 顺序 | 统一属性枚举顺序 | ⭐⭐ |