前面两篇咱们已经了解了ES6—ES8的常用新特性:
        ES新特性系列(一)—— ES的简介与ES6

        ES新特性系列(二)—— ES7、ES8

        有兴趣的彦祖们可以跳转了解。本期咱们接着聊ES9、ES10的新特性。

                                                

es版本对应client版本_es版本对应client版本

一、ES9(ECMAScript 2018)常用新特性

1.异步迭代(Asynchronous Iteration)

        异步迭代的出现主要是为了解决异步数据流的处理问题。

        传统Javascript中的for...of...循环只能处理同步的数据结构,我们看下面这个简单的例子:

const promises = [Promise.resolve('data1'), Promise.resolve('data2'), Promise.resolve('data3')];

for (let promise of promises) {
  console.log(promise);
}   
// 输出结果
// Promise {<fulfilled>: 'data1'}
// Promise {<fulfilled>: 'data2'}
// Promise {<fulfilled>: 'data3'}

       因为上述代码是同步执行,所以输出结果是立即输出,并且输出Promise的结果,而直接就是Promise本身,这显然不是咱们想要的结果。这时候咱们就要看ES9引入的异步迭代: for await...of 循环了。

        异步迭代允许我们以同步的编程方式来处理异步的数据。这大大简化了异步编程,并使得代码更易读和理解。同样以上述例子来看看异步迭代处理的结果:

const promises = [Promise.resolve('data1'), Promise.resolve('data2'), Promise.resolve('data3')];

// 使用 for await...of 循环
async function processPromises() {
  for await (let result of promises) {
    console.log(result);
  }
}

processPromises();  // 结果:data1、data2、data3,您可以复制代码在控制台试一下

         await关键词允许我们在循环之前等待异步操作得出结果,再进行处理,项目中合理使用异步迭代可以大大提高咱们的代码简洁和可读性。

2.Promise.prototype.finally()

         这个特性大家在项目中应该都经常使用,它的作用相当于给Promise的所有操作做“收尾”的工作,通常用于在 Promise 完成(无论是 fulfilled 还是 rejected)后执行某些操作。

         举个简单的例子:如果你给一个提交按钮设置了loading——在提交数据到结果返回之前按钮都是在loading状态,当结果返回时,无论是提交成功还是处理失败,都需要取消按钮的loading状态才行,此时我们就需要用到 .finally() :

submit(data) { // 确认
      this.loading = true
      method(data).then(res => {
         console.log(res.code)
      }).finally(() => {
        this.loading = false
      })
    }
 3.Rest/Spread 属性

          咱们初学的话可以将它看作是拓展运算符升级版,回忆一下ES6的拓展运算符——它允许在数组中操作,而此时升级后的拓展运算符,它允许我们在对象中对进行操作。

1.Spread 属性:Spread 操作符在对象中的应用,可以用于从一个对象创建一个新对象,同时添加、覆盖或组合属性。例如:

const obj1 = { a: 1, b: 2, c: 4 };
const obj2 = { ...obj1, c: 3 };  
const obj3 = { c: 3, ...obj1 };  

console.log(obj2)   // { a: 1, b: 2, c: 3 } 
console.log(obj3)   // { c: 4, a: 1, b: 2 }  你注意到差别了吗?

2.Rest 属性:Rest 操作符在对象中的应用,可以用于从一个对象中提取出剩余的属性到一个新的对象中。例如:

const obj = { a: 1, b: 2, c: 3 };
const { a, ...rest } = obj;  // rest: { b: 2, c: 3 }
4. 命名捕获组(Named Capture Groups)

        这个特性主要是正则表达式上的升级:在这之前,我们只能使用数字索引(如 match[1])来访问捕获组。但是,当正则表达式变得复杂,或者你修改了捕获组的顺序,使用数字索引就会变得困难和混乱。例如:

let re = /(\d{4})-(\d{2})-(\d{2})/;
let match = re.exec('2022-01-01');

let year = match[1]; // "2022"
let month = match[2]; // "01"
let day = match[3]; // "01"

       然后我们可能有项目需要要调整时间格式:

let re = /(\d{2})-(\d{2})-(\d{4})/;
let match = re.exec('01-01-2022');

let month = match[1]; // "01"
let day = match[2]; // "01"
let year = match[3]; // "2022"

       这时我们发现输出的month、year、day顺序完全不对了。有的彦祖说我一个一个手动再把索引改了不就得了,但是如果是100个数据呢?如果是项目全局需要改呢?这样傻傻改索引很麻烦且容易出错。接下来咱们用命名捕获组来解决该问题:

let re = /(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/;
let match = re.exec('01-01-2022');

let year = match.groups.year; // "2022"
let month = match.groups.month; // "01"
let day = match.groups.day; // "01"

      在这个例子中,(?<year>\d{4})、(?<month>\d{2}) (?<day>\d{2}) 是命名捕获组。?<year>、?<month> ?<day> 是捕获组的名称,而 \d{4}、\d{2} 和 \d{2} 是捕获组的模式。在执行匹配后,你可以通过 match.groups.year、match.groups.month match.groups.day 来访问捕获组的值。

      由此,无论上面的正则中的顺序如何修改,我们下面的year、month、day都可以准确的获取到对应的值,大大降低了我们对代码的维护成本,并且可读性强。

二、ES10(ECMAScript 2019)常用新特性

1.对象方法:Object.fromEntries()

      还记得咱们再上一篇ES8的特性中讲到过Object.entries()的方法吗?它可以返回对象键值对的二维数组:

const obj = {a: 1, b: 2, c: 3}
console.log(Object.entries(obj)); // 输出:[['a', 1], ['b', 2], ['c', 3]]

     Object.fromEntries()就是Object.entries()的反向操作:它可以将一个二维的键值对数组转化为对象:

const arr = [['a', 1], ['b', 2], ['c', 3]]
console.log(Object.fromEntries(arr)) // {a: 1, b: 2, c: 3}
2.数组方法:Array.prototype.flat() 和 Array.prototype.flatMap()

     两个都是数组扁平化的方法,flat() 方法用于将嵌套的数组“拉平”。

const arr = [1, [2, [3, [4]], 5]];

console.log(arr.flat());  // [1, 2,[3,[4]], 5]
console.log(arr.flat(2));  // [1, 2,3,[4], 5]
console.log(arr.flat(Infinity));  // [1, 2, 3, 4, 5]

      Array.prototype.flat() 可以输入参数,默认为1。(其中的Infinity相当于一个全局的无穷数)。

     flatMap() flat()map()合起来的方法:先执行map操作,然后再对结果进行flat()操作:

const arr = [1, 2, 3, 4];
const result = arr.flatMap(x => [x, x * 2]);

console.log(result); // 输出: [1, 2, 2, 4, 3, 6, 4, 8]
3.String.prototype.trimStart() 和 String.prototype.trimEnd()

      这两个方法用于去除字符串开始和结束处的空白字符。

const str = '   foo   ';
console.log(str.trimStart());  // "foo   "
console.log(str.trimEnd());    // "   foo"
4.新的基本数据类型 BigInt

       之前,JavaScript 中的所有数字都是 Number 类型,这种类型只能安全地表示 -(2^53 - 1) 到 2^53 - 1 范围内的整数。超出这个范围,Number 类型将无法精确表示整数。但是BigInt可以解决,不过项目中应该也不会太常用,了解即可:

// 使用 BigInt 字面量创建 BigInt
const a = 1234567890123456789012345678901234567890n;

// 使用 BigInt 函数创建 BigInt
const b = BigInt("1234567890123456789012345678901234567890");

console.log(a === b); // 输出:true

// BigInt 还支持常见的算数运算
const c = a + b;
console.log(c); // 输出:2469135780246913578024691357802469135780n
5.可选的 catch 绑定

       在之前的 ECMAScript 版本中,catch 子句必须包含一个异常变量。而在 ES10 中,如果你不需要访问这个异常变量,你可以省略它。

try {
  throw 'error';
} catch {
  console.log('An error occurred');
}
6.Function.prototype.toString() 的更新

       在 ES10 中,Function.prototype.toString() 方法返回的结果现在包含函数的注释。

function exampleFunction() {
  // 这是一个示例函数
  console.log('Hello, world!');
}

console.log(exampleFunction.toString());

// 输出为
 "function exampleFunction() {
  // 这是一个示例函数
  console.log('Hello, world!');
}"
7.全局对象globalThis

        一个新的全局对象,不论当前代码在何处运行,都可以用它来访问全局对象。

globalThis.myGlobalVariable = 'Hello, world!';

console.log(myGlobalVariable);  // 输出:'Hello, world!'

       在这个例子中,myGlobalVariable 是一个全局变量,可以在任何地方访问,无论是在函数内部,还是在模块中。

8.Symbol.prototype.description

   它提供了一种获取 Symbol 描述的方法。

let mySymbol = Symbol('my description');
console.log(mySymbol.description); // 输出 "my description"

三、总结

       本期ES9、ES10的常用新特性就给大家介绍到这里了,如果大家觉得不错,就请点赞关注一下吧。后续将继续为大家带来前端相关的内容,如有疑问,可以评论回复。