iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >2022发布ECMAScript新特性盘点
  • 579
分享到

2022发布ECMAScript新特性盘点

2024-04-02 19:04:59 579人浏览 薄情痞子
摘要

目录引言1. Top-level Await2. Object.hasOwn()3. at()4. error.cause5. 正则表达式匹配索引6. 类的实例成员(1)公共实例字段

引言

2022 年 6 月 22 日,第 123 届 ECMA 大会批准了 ECMAScript 2022 语言规范,这意味着它现在正式成为标准。下面就来看看 ECMAScript 2022 新增了哪些特性!

总览:

  • Top-level Await
  • Object.hasOwn()
  • at()
  • error.cause
  • 正则表达式匹配索引
  • 类的实例成员

1. Top-level Await

在ES2017中,引入了 async 函数和 await 关键字,以简化 Promise 的使用,但是 await 关键字只能在 async 函数内部使用。尝试在异步函数之外使用 await 就会报错:

SyntaxError - SyntaxError: await is only valid in async function。

顶层 await 允许我们在 async 函数外面使用 await 关键字。它允许模块充当大型异步函数,通过顶层 await,这些 ECMAScript 模块可以等待资源加载。这样其他导入这些模块的模块在执行代码之前要等待资源加载完再去执行。

由于 await 仅在 async 函数中可用,因此模块可以通过将代码包装在 async 函数中来在代码中包含 await

  // a.js
  import fetch  from "node-fetch";
  let users;
  export const fetchUsers = async () => {
    const resp = await fetch('https://JSONplaceholder.typicode.com/users');
    users =  resp.json();
  }
  fetchUsers();
  export { users };
  // usingAwait.js
  import {users} from './a.js';
  console.log('users: ', users);
  console.log('usingAwait module');

我们还可以立即调用顶层async函数(IIAFE):

import fetch  from "node-fetch";
  (async () => {
    const resp = await fetch('Https://jsonplaceholder.typicode.com/users');
    users = resp.json();
  })();
  export { users };

这样会有一个缺点,直接导入的 usersundefined,需要在异步执行完成之后才能访问它:

// usingAwait.js
import {users} from './a.js';
console.log('users:', users); // undefined
setTimeout(() => {
  console.log('users:', users);
}, 100);
console.log('usingAwait module');

当然,这种方法并不安全,因为如果异步函数执行花费的时间超过100毫秒, 它就不会起作用了,users 仍然是 undefined

另一个方法是导出一个 promise,让导入模块知道数据已经准备好了:

//a.js
import fetch  from "node-fetch";
export default (async () => {
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
  users = resp.json();
})();
export { users };
//usingAwait.js
import promise, {users} from './a.js';
promise.then(() => { 
  console.log('usingAwait module');
  setTimeout(() => console.log('users:', users), 100); 
});

虽然这种方法似乎是给出了预期的结果,但是有一定的局限性:导入模块必须了解这种模式才能正确使用它

而顶层await就可以解决这些问题:

  // a.js
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
  const users = resp.json();
  export { users};
  // usingAwait.js
  import {users} from './a.mjs';
  console.log(users);
  console.log('usingAwait module');

顶级 await 在以下场景中将非常有用:

  • 动态加载模块:
 const strings = await import(`/i18n/${navigator.language}`);
  • 资源初始化:
const connection = await dbConnector();
  • 依赖回退:
let translations;
try {
  translations = await import('https://app.fr.json');
} catch {
  translations = await import('https://fallback.en.json');
}

该特性的浏览器支持如下:

2. Object.hasOwn()

在ES2022之前,可以使用 Object.prototype.hasOwnProperty() 来检查一个属性是否属于对象。

Object.hasOwn 特性是一种更简洁、更可靠的检查属性是否直接设置在对象上的方法:

const example = {
  property: '123'
};
console.log(Object.prototype.hasOwnProperty.call(example, 'property'));
console.log(Object.hasOwn(example, 'property'));

该特性的浏览器支持如下:

3. at()

at() 是一个数组方法,用于通过给定索引来获取数组元素。当给定索引为正时,这种新方法与使用括号表示法访问具有相同的行为。当给出负整数索引时,就会从数组的最后一项开始检索:

const array = [0,1,2,3,4,5];
console.log(array[array.length-1]);  // 5
console.log(array.at(-1));  // 5
console.log(array[array.lenght-2]);  // 4
console.log(array.at(-2));  // 4

除了数组,字符串也可以使用at()方法进行索引:

const str = "hello world";
console.log(str[str.length - 1]);  // d
console.log(str.at(-1));  // d

4. error.cause

在 ECMAScript 2022 规范中,new Error() 中可以指定导致它的原因:

function readFiles(filePaths) {
  return filePaths.map(
    (filePath) => {
      try {
        // ···
      } catch (error) {
        throw new Error(
          `While processing ${filePath}`,
          {cause: error}
        );
      }
    });
}

5. 正则表达式匹配索引

该特性允许我们利用 d 字符来表示我们想要匹配字符串的开始和结束索引。以前,只能在字符串匹配操作期间获得一个包含提取的字符串和索引信息的数组。在某些情况下,这是不够的。因此,在这个规范中,如果设置标志 /d,将额外获得一个带有开始和结束索引的数组。

const matchObj = /(a+)(b+)/d.exec('aaaabb');
console.log(matchObj[1]) // 'aaaa'
console.log(matchObj[2]) // 'bb'

由于 /d 标识的存在,matchObj还有一个属性.indices,它用来记录捕获的每个编号组:

console.log(matchObj.indices[1])  // [0, 4]
console.log(matchObj.indices[2])  // [4, 6]

我们还可以使用命名组:

const matchObj = /(?<as>a+)(?<bs>b+)/d.exec('aaaabb');
console.log(matchObj.groups.as);  // 'aaaa'
console.log(matchObj.groups.bs);  // 'bb'

这里给两个字符匹配分别命名为asbs,然后就可以通过groups来获取到这两个命名分别匹配到的字符串。

它们的索引存储在 matchObj.indices.groups 中:

console.log(matchObj.indices.groups.as);  // [0, 4]
console.log(matchObj.indices.groups.bs);  // [4, 6]

匹配索引的一个重要用途就是指向语法错误所在位置的解析器。下面的代码解决了一个相关问题:它指向引用内容的开始和结束位置。

const reQuoted = /“([^”]+)”/dgu;
function pointToQuotedText(str) {
  const startIndices = new Set();
  const endIndices = new Set();
  for (const match of str.matchAll(reQuoted)) {
    const [start, end] = match.indices[1];
    startIndices.add(start);
    endIndices.add(end);
  }
  let result = '';
  for (let index=0; index < str.length; index++) {
    if (startIndices.has(index)) {
      result += '[';
    } else if (endIndices.has(index+1)) {
      result += ']';
    } else {
      result += ' ';
    }
  }
  return result;
}
console.log(pointToQuotedText('They said “hello” and “Goodbye”.'));
// '           [   ]       [     ]  '

6. 类的实例成员

(1)公共实例字段

公共类字段允许我们使用赋值运算符 (=) 将实例属性添加到类定义中。下面是一个计数器的例子:

import React, { Component } from "react";
export class Incrementor extends Component {
  constructor() {
    super();
    this.state = {
      count: 0,
    };
    this.increment = this.increment.bind(this);
  }
  increment() {
    this.setState({ count: this.state.count + 1 });
  }
  render() {
    return (
      <button onClick={this.increment}>Increment: {this.state.count}</button>
    );
  }
}

在这个例子中,在构造函数中定义了实例字段和绑定方法,通过新的类语法,可以使代码更加直观。新的公共类字段语法允许我们直接将实例属性作为属性添加到类上,而无需使用构造函数方法。这样就简化了类的定义,使代码更加简洁、可读:

import React from "react";
export class Incrementor extends React.Component {
  state = { count: 0 };
  increment = () => this.setState({ count: this.state.count + 1 });
  render = () => (
    <button onClick={this.increment}>Increment: {this.state.count}</button>
  );
}

有些小伙伴可能就疑问了,这个功能很早就可以使用了呀。但是它现在还不是标准的 ECMAScript,默认是不开启的,如果使用 create-react-app 创建 React 项目,那么它默认是启用的,否则我们必须使用正确的babel插件才能正常使用(@babel/preset-env)。

下面来看看关于公共实例字段的注意事项:

  • 公共实例字段存在于每个创建的类实例上。它们要么是在Object.defineProperty()中添加,要么是在基类中的构造时添加(构造函数主体执行之前执行),要么在子类的super()返回之后添加:
class Incrementor {
  count = 0
}
const instance = new Incrementor();
console.log(instance.count); // 0
  • 未初始化的字段会自动设置为 undefined
class Incrementor {
  count
}
const instance = new Incrementor();
console.assert(instance.hasOwnProperty('count'));
console.log(instance.count);  // undefined
  • 可以进行字段的计算:
const PREFIX = 'main';
class Incrementor {
  [`${PREFIX}Count`] = 0
}
const instance = new Incrementor();
console.log(instance.mainCount);   // 0

(2)私有实例字段、方法和访问器

默认情况下,es6 中所有属性都是公共的,可以在类外检查或修改。下面来看一个例子:

class TimeTracker {
  name = 'zhangsan';
  project = 'blog';
  hours = 0;
  set addHours(hour) {
    this.hours += hour;
  }
  get timeSheet() {
    return `${this.name} works ${this.hours || 'nothing'} hours on ${this.project}`;
  }
}
let person = new TimeTracker();
person.addHours = 2; // 标准 setter
person.hours = 4;    // 绕过 setter 进行设置
person.timeSheet;

可以看到,在类中没有任何措施可以防止在不调用 setter 的情况下更改属性。

而私有类字段将使用哈希#前缀定义,从上面的示例中,可以修改它以包含私有类字段,以防止在类方法之外更改属性:

class TimeTracker {
  name = 'zhangsan';
  project = 'blog';
  #hours = 0;  // 私有类字段
  set addHours(hour) {
    this.#hours += hour;
  }
  get timeSheet() {
    return `${this.name} works ${this.#hours || 'nothing'} hours on ${this.project}`;
  }
}
let person = new TimeTracker();
person.addHours = 4; // 标准 setter
person.timeSheet     // zhangsan works 4 hours on blog

当尝试在 setter 方法之外修改私有类字段时,就会报错:

person.hours = 4 // Error Private field '#hours' must be declared in an enclosing class

还可以将方法或 getter/setter 设为私有,只需要给这些方法名称前面加#即可:

class TimeTracker {
  name = 'zhangsan';
  project = 'blog';
  #hours = 0;   // 私有类字段
  set #addHours(hour) {
    this.#hours += hour;
  }
  get #timeSheet() {
    return `${this.name} works ${this.#hours || 'nothing'} hours on ${this.project}`;
  }
  constructor(hours) {
    this.#addHours = hours;
    console.log(this.#timeSheet);
  }
}
let person = new TimeTracker(4); // zhangsan works 4 hours on blog

由于尝试访问对象上不存在的私有字段会发生异常,因此需要能够检查对象是否具有给定的私有字段。可以使用 in 运算符来检查对象上是否有私有字段:

class Example {
  #field
  static isExampleInstance(object) {
    return #field in object;
  }
}

(3)静态公共字段

在ES6中,不能在类的每个实例中访问静态字段或方法,只能在原型中访问。ES 2022 提供了一种在 javascript 中使用 static 关键字声明静态类字段的方法。下面来看一个例子:

class Shape {
  static color = 'blue';
  static getColor() {
    return this.color;
  }
  getMessage() {
    return `color:${this.color}` ;
  }
}

可以从类本身访问静态字段和方法:

  console.log(Shape.color); // blue
  console.log(Shape.getColor()); // blue
  console.log('color' in Shape); // true
  console.log('getColor' in Shape); // true
  console.log('getMessage' in Shape); // false

实例不能访问静态字段和方法:

  const shapeInstance = new Shape();
  console.log(shapeInstance.color); // undefined
  console.log(shapeInstance.getColor); // undefined
  console.log(shapeInstance.getMessage());// color:undefined

静态字段只能通过静态方法访问:

console.log(Shape.getColor()); // blue
console.log(Shape.getMessage()); //TypeError: Shape.getMessage is not a function

这里的 Shape.getMessage() 就报错了,因为 getMessage 不是一个静态函数,所以它不能通过类名 Shape 访问。可以通过以下方式来解决这个问题:

getMessage() {
  return `color:${Shape.color}` ;
}

静态字段和方法是从父类继承的:

class Rectangle extends Shape { }
console.log(Rectangle.color); // blue
console.log(Rectangle.getColor()); // blue
console.log('color' in Rectangle); // true
console.log('getColor' in Rectangle); // true
console.log('getMessage' in Rectangle); // false

(4)静态私有字段和方法

与私有实例字段和方法一样,静态私有字段和方法也使用哈希 (#) 前缀来定义:

class Shape {
  static #color = 'blue';
  static #getColor() {
    return this.#color;
  }
  getMessage() {
    return `color:${Shape.#getColor()}` ;
  }
}
const shapeInstance = new Shape();
shapeInstance.getMessage(); // color:blue

私有静态字段有一个限制:只有定义私有静态字段的类才能访问该字段。这可能在使用 this 时导致出乎意料的情况:

class Shape {
  static #color = 'blue';
static #getColor() {
  return this.#color;
}
static getMessage() {
  return `color:${this.#color}` ;
}
getMessageNonStatic() {
  return `color:${this.#getColor()}` ;
}
}
class Rectangle extends Shape {}
console.log(Rectangle.getMessage()); // Uncaught TypeError: Cannot read private member #color from an object whose class did not declare it
const rectangle = new Rectangle();
console.log(rectangle.getMessageNonStatic()); // TypeError: Cannot read private member #getColor from an object whose class did not declare it

在这个例子中,this 指向的是 Rectangle 类,它无权访问私有字段 #color。当我们尝试调用 Rectangle.getMessage() 时,它无法读取 #color 并抛出了 TypeError。可以这样来进行修改:

class Shape {
  static #color = 'blue';
  static #getColor() {
    return this.#color;
  }
  static getMessage() {
    return `${Shape.#color}`;
  }
  getMessageNonStatic() {
    return `color:${Shape.#getColor()} color`;
  }
}
class Rectangle extends Shape {}
console.log(Rectangle.getMessage()); // color:blue
const rectangle = new Rectangle();
console.log(rectangle.getMessageNonStatic()); // color:blue

(5)类静态初始化块

静态私有和公共字段只能让我们在类定义期间执行静态成员的每个字段初始化。如果我们需要在初始化期间像 try…catch 一样进行异常处理,就不得不在类之外编写此逻辑。该规范就提供了一种在类声明/定义期间评估静态初始化代码块的优雅方法,可以访问类的私有字段。

先来看一个例子:

class Person {
    static GENDER = "Male"
    static TOTAL_EMPLOYED;
    static TOTAL_UNEMPLOYED;
    try {
        // ...
    } catch {
        // ...
    }
}

上面的代码就会引发错误,可以使用类静态块来重构它,只需将try...catch包裹在 static 中即可:

class Person {
    static GENDER = "Male"
    static TOTAL_EMPLOYED;
    static TOTAL_UNEMPLOYED;
  static {
  	try {
        // ...
    } catch {
        // ...
    }
  }
}

此外,类静态块提供对词法范围的私有字段和方法的特权访问。这里需要在具有实例私有字段的类和同一范围内的函数之间共享信息的情况下很有用。

let getData;
class Person {
  #x
  constructor(x) {
    this.#x = { data: x };
  }
  static {
    getData = (obj) => obj.#x;
  }
}
function readPrivateData(obj) {
  return getData(obj).data;
}
const john = new Person([2,4,6,8]);
readPrivateData(john); // [2,4,6,8]

这里,Person 类与 readPrivateData 函数共享了私有实例属性。

以上就是2022发布ECMAScript新特性盘点的详细内容,更多关于ECMAScript新特性的资料请关注编程网其它相关文章!

--结束END--

本文标题: 2022发布ECMAScript新特性盘点

本文链接: https://www.lsjlt.com/news/153386.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 2022发布ECMAScript新特性盘点
    目录引言1. Top-level Await2. Object.hasOwn()3. at()4. error.cause5. 正则表达式匹配索引6. 类的实例成员(1)公共实例字段...
    99+
    2024-04-02
  • ECMAScript新特性有哪些
    本篇内容介绍了“ECMAScript新特性有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. Top-level Await在ES20...
    99+
    2023-07-02
  • ECMAscript新特性对象介绍
    目录1.对象的属性 1.1属性表示法 2.计算属性名 3.Object 的方法 3.1Object.is() 方法 3.2Object.assign()方法 4.super 关键字 ...
    99+
    2024-04-02
  • iOS StoreKit 2 新特性盘点解析
    目录一、背景二、物料三、StoreKit 1 存在的问题四、StoreKit v2 新特性五、StoreKit 2 API5.1 只支持 Swift 开发原始获取商品方式新获取商品方...
    99+
    2024-04-02
  • JavaScript ECMAScript 6(ES2015~ES2022)所有新特性总结
    目录前言ES2015(ES6)let、const关键字和块级作用域函数的扩展数值的扩展字符串的扩展数组的扩展对象的扩展类模块化解构赋值SymbolPromiseIteratorGen...
    99+
    2024-04-02
  • Laravel 10 正式发布(新特性介绍)
    Laravel 10现已发布,包括最低要求的PHP v8.1版本、新的Laravel Pennant软件包、可调用的验证规则、本地类型声明等等。Laravel发布计划在Laravel 9之前,主要的框架版本每年发布两次,或者大约每六个月发布...
    99+
    2023-03-06
    Laravel 10 Laravel10 Laravel升级
  • Spring Boot3.0正式发布及新特性解读
    Spring Boot 3.0 正式发布 同时发布更新的还有 2.7.x 和 2.6.x 两条版本线,Spring Boot 是我见过的发版最守时的技术框架之一。 Spring Boot 3.0 现已正式发布,它包含了 12 个月以来 ...
    99+
    2023-09-04
    spring boot java spring
  • PHP8发布,新特性亮点一览,让您紧跟技术潮流
    PHP8发布,新特性亮点一览,让您紧跟技术潮流前言:作为一种广泛使用的编程语言,PHP一直在不断发展和改进。不久前,PHP8正式发布,为广大开发者带来了许多令人激动的新特性和改进。本文将为大家介绍PHP8的一些亮点,同时提供具体的代码示例,...
    99+
    2023-12-23
    PHP 特性 新增
  • Debian 10 Buster发布版的新特点是什么
    本篇文章给大家分享的是有关Debian 10 Buster发布版的新特点是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Debian 10 Buster 即将发布。发布候选...
    99+
    2023-06-16
  • Ubuntu Tweak 0.7.3发布的新特性有哪些呢
    本篇文章给大家分享的是有关Ubuntu Tweak 0.7.3发布的新特性有哪些呢,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Ubuntu Tweak 0.7.3正式发布了,...
    99+
    2023-06-16
  • Qemu0.10.0发布有哪些特点
    这篇文章主要介绍Qemu0.10.0发布有哪些特点,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Qemu 团队已发布 0.10.0 版本。该版本历经一年多的开发,从 80 位开发者带来了几近 3000 个改动。Qem...
    99+
    2023-06-17
  • MySQL 8.0 正式版发布的新特性有哪些
    这篇文章将为大家详细讲解有关MySQL 8.0 正式版发布的新特性有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。MySQL 8.0 正式版 8.0.1...
    99+
    2024-04-02
  • SQL Server 2022 AlwaysOn新特性之包含可用性组详解
    目录1 如何创建包含可用性组?2 如何使用包含可用性组?3 元数据同步验证3.1 用户、登录名和权限3.2 链接服务器3.3 SQL代理作业4 包含可用性组总结SQL Server的...
    99+
    2023-05-18
    SQL Server 2022 AlwaysOn  SQL Server 2022可用性
  • SQL Server 2022 AlwaysOn新特性之包含可用性组详解
    目录1 如何创建包含可用性组?2 如何使用包含可用性组?3 元数据同步验证3.1 用户、登录名和权限3.2 链接服务器3.3 SQL代理作业4 包含可用性组总结SQL Server的容灾功能一直弱于oracle和mysq...
    99+
    2023-04-28
    SQL Server 2022 AlwaysOn SQL Server 2022可用性
  • Java8并发新特性CompletableFuture
    目录1.CompletableFuture是什么?2.CompletableFuture的方法使用说明2.1 CompletableFuture类提供几个静态方法来进行异步操作2.2...
    99+
    2024-04-02
  • JDK21发布了!面试官:来,谈下jdk21的新特性!
    1.前言 JDK21 计划23年9月19日正式发布,尽管一直以来都是“版随意出,换 8 算我输”,但这么多年这么多版本的折腾,若是之前的 LTS 版本JDK17你还觉得不错,那 JDK21还是...
    99+
    2023-10-06
    后端
  • 【MySQL】MySQL8.1.0版本正式发布带来哪些新特性?
    文章目录 前言一、畅谈新版本二、8.1.0版本部署2.1、环境准备2.2、配置yum安装依赖2.3、用户及目录创建2.4、创建用户及组2.5、解压缩包2.6、环境变量配置2.7、创建参数文件2.8、数据库初始化2.9、启动Mysql...
    99+
    2023-08-16
    mysql
  • web开发中新时代布局的特性有哪些
    本篇文章给大家分享的是有关web开发中新时代布局的特性有哪些,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。在最新的 Chrome Canary...
    99+
    2024-04-02
  • Python 3.10发布!你应该知道这5大新特性
    Python 在市场上已经有一段时间了,作为一名 Python 开发人员,我很高兴地分享 Python 正在逐步获得更新和每个新版本的改进。Python 的最新版本 3.10 有一些重大改进,我将在此处列出这些更新。我在列举了这个新版本 的...
    99+
    2023-05-14
    Python 新版本 特性
  • Python Django的未来:即将发布的新特性和改进
    Django 8.0的即将发布的新特性和改进 Django 8.0是一个备受期待的版本,它将带来许多令人兴奋的新特性和改进。其中一些即将发布的新特性和改进包括: 改进的管理界面:Django 8.0将对管理界面进行重大改进,使其更加用户...
    99+
    2024-02-26
    Python Django 新特性 改进 Web框架
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作