ES11 新特性:
1. 可选链操作符 ?.:在访问对象的属性或方法时,可以使用可选链操作符来避免因为对象不存在或属性不存在导致的异常错误。
JS可选链操作符 ?.用于简化在访问可能为null或undefined的对象或属性时的代码。它的主要使用方法如下:
- 访问嵌套的属性或方法
const obj = {
prop1: {
prop2: {
prop3: 'value'
}
}
};
const propValue = obj?.prop1?.prop2?.prop3; // 'value'
在ES12新出了可选链操作符 ?. 的升级:支持对函数的调用、数组的访问和对值类型的存取
如果嵌套的属性或方法不存在,那么可选链操作符会返回undefined,而不是抛出TypeError。
- 调用函数(方法)
const obj = {
prop1: {
doSomething: () => 'done'
}
};
const result = obj?.prop1?.doSomething?.(); // 'done'
如果函数不存在,那么调用会被跳过,以避免抛出TypeError。
- 处理数组
const arr = [
{ name: 'Peter', age: 25 },
{ name: 'John', age: 30 },
null,
undefined
];
const age = arr[1]?.age; // 30
const nonExistent = arr[3]?.nonExistent?.property; // undefined
在访问数组中的元素时,可选链操作符可以防止抛出TypeError。
除此之外,可选链操作符还可以用于访问对象的Symbol属性和Proxy代理对象中的属性等。需要注意的是,可选链操作符在ES2020中才被引入,因此有些浏览器或Node.js版本可能不支持它。可以使用Babel等工具进行转译。
2. Nullish coalescing 操作符 ??:用于判断变量是否为 null 或者 undefined,并给出默认值。
Nullish coalescing 操作符 ?? 可以用来检查一个值是否为 null 或 undefined,如果是,则返回默认值,如果不是,则返回该值。
使用方法如下:
let variable1 = null;
let variable2 = undefined;
let variable3 = 0;
let variable4 = '';
console.log(variable1 ?? 'default value'); // 输出 'default value'
console.log(variable2 ?? 'default value'); // 输出 'default value'
console.log(variable3 ?? 'default value'); // 输出 0
console.log(variable4 ?? 'default value'); // 输出 ''
在上面的例子中,变量 variable1
和 variable2
的值为 null 和 undefined,所以使用 ?? 操作符返回了指定的默认值。变量 variable3
和 variable4
的值不是 null 或 undefined,所以返回了它们的原始值。
3. Promise.allSettled() 方法:可以接收一组 Promise,不管 Promise 是否被解析,都会返回一个状态为“已解析”的 Promise 数组。
Promise.allSettled() 方法接受一个 Promise 数组,它返回一个新的 Promise 对象,该对象将在所有 Promise 完成或拒绝后解决。与 Promise.all() 不同的是,即使其中一些 Promise 被拒绝,返回的 Promise 仍将被解决。返回的 Promise 将解决一个带有所有 Promise 结果的数组,每个 Promise 结果都是一个带有以下属性的对象:
status
:表示 Promise 的状态,可以是 “fulfilled” 或 “rejected”。value
(如果状态为 “fulfilled”):表示解决的值。reason
(如果状态为 “rejected”):表示拒绝的原因。
下面是 Promise.allSettled() 方法的使用方法:
Promise.allSettled(promises)
.then(results => {
results.forEach(result => {
if (result.status === "fulfilled") {
console.log(`Promise resolved with value: ${result.value}`);
} else {
console.log(`Promise rejected with reason: ${result.reason}`);
}
});
})
.catch(error => console.error(error));
其中,promises
是一个 Promise 数组,results
是一个带有所有 Promise 结果的数组。在结果数组中,每个 Promise 结果可以访问 status
、value
或 reason
属性,以根据 Promise 的状态确定结果。在 .then() 方法中,您可以使用 forEach() 循环来遍历每个 Promise 结果并执行相应的操作。
如果 Promise 数组中任何一个 Promise 被拒绝,则在返回的 Promise 上调用的 .catch() 方法将捕获该错误。
4. String.prototype.replaceAll() 方法:用于替换字符串中所有匹配的子字符串。
String.prototype.replaceAll() 方法是用于替换字符串中所有匹配的子字符串的方法。该方法需要传入两个参数:要匹配的子字符串和用来替换匹配的字符串。它返回一个新的字符串,该字符串是由原字符串中所有匹配的子字符串替换成指定字符串后的结果。
使用示例:
const str = 'hello world!';
const newStr = str.replaceAll('l', 'x');
console.log(newStr); // 'hexxo worxd!'
在上面的例子中,我们调用了 replaceAll()
方法来将 str
中所有的 l
字符替换成 x
字符。执行结果为 'hexxo worxd!'
。
需要注意的是,该方法是在 ES2021 中引入的,因此在一些旧的浏览器版本中可能不支持,需要使用 polyfill 或其他替代方案来实现。
ES12 新特性:
1. 可选链操作符 ?. 的升级:支持对函数的调用、数组的访问和对值类型的存取。(见上)
2. Promise.any() 方法:在传入的一组 Promise 中至少有一个解析(或拒绝)时才会返回 Promise 解析的方法。
Promise.any() 方法接收一个 Promise 对象数组,返回数组中第一个成功的 Promise 对象的值。如果所有 Promise 对象都失败了,则返回一个 AggregateError 对象,其中包含所有 Promise 对象的 rejection 原因。
以下是 Promise.any() 方法的用法示例:
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.reject('Error 3');
Promise.any([promise1, promise2, promise3])
.then(result => console.log(result))
.catch(error => console.log(error));
// Output:
// 1
在上述示例中,我们创建了三个 Promise 对象,其中 promise1 和 promise2 成功地解决并返回它们的值,而 promise3 失败并抛出一个错误。使用 Promise.any() 方法,我们传递了一个包含这三个 Promise 对象的数组。由于 promise1 和 promise2 都成功了,Promise.any() 方法返回第一个成功的 Promise 对象的值,也就是 1。
如果我们将 promise3 从数组中移除,则 Promise.any() 方法就会抛出一个 AggregateError 对象,其中包含 promise1 和 promise2 的 rejection 原因。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.reject('Error 3');
Promise.any([promise1, promise2])
.then(result => console.log(result))
.catch(error => console.log(error));
// Output:
// AggregateError: All promises were rejected
// at <anonymous>
// at processTicksAndRejections (internal/process/task_queues.js:97:5)
需要注意的是,Promise.any() 方法是在 ES2021 中引入的,因此,在一些较旧的浏览器或 Node.js 版本中可能无法使用。
3. WeakRef 和 Finalizer API:可以使开发者更好地控制内存管理。
JavaScript中的WeakRef和Finalizer API是ES2021的新特性,它们旨在帮助开发人员更轻松地管理内存。
WeakRef允许开发人员创建一个对对象的弱引用,这意味着当对象不再被程序中的任何强引用所引用时,它将被标记为可回收。它的语法如下:
const weakRef = new WeakRef(object);
其中,object是要创建弱引用的对象。当程序中不再有任何强引用时,我们可以通过调用weakRef.deref()方法来获取弱引用指向的对象。如果对象已经被回收,deref()方法将返回undefined。
Finalizer API 允许开发人员在内存回收之前执行一些操作,比如清理资源或日志。它的语法如下:
new FinalizationRegistry(callback);
其中,callback是在对象被回收时调用的回调函数。当创建一个FinalizationRegistry对象时,它会返回一个注册对象的方法:
registry.register(object, data, [holdTime]);
其中,object是要注册的对象,data是一个任意的额外数据,holdTime是对象在没有任何强引用时保留的时间,以毫秒为单位。当对象被回收时,callback函数将被调用并传入注册时提供的data参数。
使用WeakRef和Finalizer API可以帮助开发人员更好地管理内存并清理资源。但是,由于这些API是新的,有些浏览器可能不支持它们。在使用之前,请确保您的目标平台支持这些API。
4. 数字分隔符:在数字中使用下划线作为分隔符,更容易阅读和理解数字。
JS数字分隔符是一个新的特性,它可以将数字用下划线或空格分隔成更易读的形式,而不会影响数字的值。例如:
let million = 1_000_000;
let pi = 3.14159_26535;
let binary = 0b1010_0001_1000_0101;
这里,数字1,000,000被写为1_000_000,数字3.1415926535被写为3.14159_26535,数字二进制1010000110000101被写为0b1010_0001_1000_0101。
注意,数字中的下划线不能放在数字的开头或结尾,也不能放在小数点前后,也不能在科学计数法中的e或E的前后。此外,在旧版本的浏览器中,数字分隔符可能不被支持,需要使用polyfill来实现。
5. String.prototype.matchAll() 方法:用于查找所有匹配一个正则表达式的字符串,返回一个迭代器。
JavaScript中的String.prototype.matchAll()
方法可以在字符串中检索所有匹配正则表达式模式的结果,返回一个迭代器对象,可以通过该对象依次访问每个匹配项的详细信息。
该方法接收一个正则表达式作为参数,并返回一个迭代器对象。每个匹配项都是一个数组,包含匹配的子字符串及其相关信息,例如匹配的位置、捕获组等。
下面是一个示例:
const str = "Hello world, hello JavaScript!";
const regex = /(hello) (\w+)/gi;
const matches = str.matchAll(regex);
for (const match of matches) {
console.log(match);
}
输出:
["hello world", "hello", "world", index: 0, input: "Hello world, hello JavaScript!", groups: undefined]
["hello JavaScript", "hello", "JavaScript", index: 13, input: "Hello world, hello JavaScript!", groups: undefined]
可以看到,迭代器返回了两个匹配项,每个匹配项都是一个数组,第一个元素是匹配的子字符串,接下来的元素是捕获组的值,最后是一些附加信息。在这个例子中,正则表达式匹配了两次,分别是"hello world"和"hello JavaScript"。
需要注意的是,String.prototype.matchAll()
方法是ES2018新增的方法,需要在支持该方法的浏览器或Node.js版本中使用。如果需要支持低版本的环境,可以使用RegExp.prototype.exec()
方法以及循环来实现类似的功能。
ES13 新特性:
1. BigInt:用于表示任意精度整数。(ES11就出了,放错位置了,抱歉)
BigInt 是 JavaScript 中新增的数据类型,用于表示任意精度的整数。在旧版 JavaScript 中,数字类型的最大值为 2^53 - 1,超出这个范围的整数会出现精度问题。BigInt 可以解决这个问题,可以表示任意大的整数。以下是 JS BigInt 的使用方法:
- 在数字后面加
n
表示一个 BigInt,例如1234567890n
。 - 使用
BigInt()
函数将一个数字转换成 BigInt 类型,例如BigInt(123456)
。 - BigInt 可以进行常见的数学操作,例如
+
,-
,*
,/
,%
等。 - 注意,在使用 BigInt 进行数学操作时,需要使用 BigInt 类型的变量或字面量,不能和数字类型混合计算。
下面是一个简单的示例,展示了如何使用 BigInt:
// 创建 BigInt 变量
const a = 12345678901234567890n;
const b = BigInt(9876543210);
// 进行数学操作
const c = a + b;
const d = a - b;
const e = a * b;
const f = a / b;
const g = a % b;
// 输出结果
console.log(c); // 12345678911111111100n
console.log(d); // 12345678901224791380n
console.log(e); // 121932631137021824023361955n
console.log(f); // 1249999999n
console.log(g); // 1234567880n
注意,旧版浏览器可能不支持 BigInt 数据类型。在这种情况下,可以使用第三方库,例如 bigint-polyfill
。
2. Nullish coalescing 操作符 ?? 的升级:可以支持更多的逻辑运算符。(见上)
3. Optional catch binding:在 catch 子句中声明的变量不再是强制性的,如果变量名省略,则不会创建绑定。
ES2019 引入了可选的 catch 绑定语法,可以更方便地访问 catch 块中的错误信息。在以前的版本中,我们需要在 catch 块中手动创建一个变量来存储错误信息。
Optional catch binding 可以用于以下情况:
- 如果 catch 块中不需要访问错误信息,可以省略参数。
- 如果需要访问错误信息,可以使用 catch (error) 或 catch (e) 来访问错误信息。
下面是一些使用 Optional catch binding 的例子:
try {
// some code
} catch {
// handle error
}
try {
// some code
} catch (error) {
// handle error
}
try {
// some code
} catch (e) {
// handle error
}
使用 Optional catch binding 不仅可以简化代码,而且可以使代码更清晰易懂。
4. Array.prototype.flat() 和 Array.prototype.flatMap() 方法:用于处理多维数组和映射操作。
Array.prototype.flat():
这个方法可以把一个嵌套的数组“拍平”,变成一个一维数组。它的参数是一个整数,表示要拍平的层数,默认为1。如果层数为Infinity,则会对所有嵌套进行拍平。
例如,有一个三层嵌套的数组:
const arr = [1, 2, [3, 4, [5, 6, [7, 8]]]];
使用 flat() 方法:
const newArr = arr.flat(3);
console.log(newArr); // [1, 2, 3, 4, 5, 6, 7, 8]
Array.prototype.flatMap():
这个方法可以对数组的每个元素执行一个函数,然后把执行结果“拍平”成一个新数组。它的参数是一个函数,该函数接受三个参数:当前元素、元素索引、原数组。
例如,有一个数组:
const arr = [1, 2, 3];
使用 flatMap() 方法:
const newArr = arr.flatMap(x => [x * 2]);
console.log(newArr); // [2, 4, 6]
上述例子中,我们把每个元素乘以2,然后把执行结果“拍平”成一个新数组。结果为[2, 4, 6]。注意,如果函数返回的是一个数组,flatMap() 方法会“拍平”这个数组。例如:
const arr = [1, 2, 3];
const newArr = arr.flatMap(x => [[x * 2]]);
console.log(newArr); // [[2], [4], [6]]
5. Object.fromEntries() 方法:可以将键值对数组转换成对象。
JavaScript的Object.fromEntries()方法可以将由键值对数组组成的数组转换为对象。
语法:
Object.fromEntries(iterable)
参数:
- iterable:一个可迭代对象,每个成员都是一个键值对数组。
返回值:
- 一个新的对象,其自身属性具有从iterable中的键值对所构成的。
示例:
const entries = [['a', 1], ['b', 2], ['c', 3]];
const obj = Object.fromEntries(entries);
console.log(obj); // { a: 1, b: 2, c: 3 }
在这个例子中,我们将由键值对数组组成的数组entries转换为对象obj。现在,obj中的属性就是键值对数组中的键和值。