我的编程空间,编程开发者的网络收藏夹
学习永远不晚

ECMAScript新特性有哪些

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

ECMAScript新特性有哪些

本篇内容介绍了“ECMAScript新特性有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

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.jsimport {users} from './a.js';console.log('users:', users); // undefinedsetTimeout(() => {  console.log('users:', users);}, 100);console.log('usingAwait module');

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

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

//a.jsimport fetch  from "node-fetch";export default (async () => {  const resp = await fetch('https://jsonplaceholder.typicode.com/users');  users = resp.json();})();export { users };//usingAwait.jsimport 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');}

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

ECMAScript新特性有哪些

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'));

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

ECMAScript新特性有哪些

3. at()

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

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

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

const str = "hello world";console.log(str[str.length - 1]);  // dconsole.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; // 标准 setterperson.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; // 标准 setterperson.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()); // blueconsole.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); // blueconsole.log(Rectangle.getColor()); // blueconsole.log('color' in Rectangle); // trueconsole.log('getColor' in Rectangle); // trueconsole.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 itconst 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:blueconst 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 函数共享了私有实例属性。

“ECMAScript新特性有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

ECMAScript新特性有哪些

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

下载Word文档

猜你喜欢

ECMAScript新特性有哪些

本篇内容介绍了“ECMAScript新特性有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. Top-level Await在ES20
2023-07-02

html5有哪些新特性

html5的新特性有:1、语义化标签(hrader、footer等),使得页面的内容结构化,见名知义;2、增强型表单,拥有多个新的表单Input输入类型,可提供更好的输入控制和验证;3、video和audio元素,提供了播放视频和音频文件的标准方法;4、Canvas绘图;5、SVG绘图;6、地理定位;7、拖放API;8、Web Worker;9、Web Storage等等。
2023-05-14

HTML5新特性有哪些

本篇内容主要讲解“HTML5新特性有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML5新特性有哪些”吧!Web存储 它具有以下特征: 你可以通过属性和方法来使用 JavaScript
2023-06-04

JDK1.5有哪些新特性

本篇内容主要讲解“JDK1.5有哪些新特性”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JDK1.5有哪些新特性”吧!  1.泛型(Generic)  C++通过模板技术可以指定集合的元素类型,
2023-06-03

JMS新特性有哪些

这篇文章主要为大家展示了“JMS新特性有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JMS新特性有哪些”这篇文章吧。JMS(Java Message Service,Java消息服务)是J
2023-06-17

FlexBuilder4新特性有哪些

这篇文章给大家分享的是有关FlexBuilder4新特性有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。FlexBuilder4新特性在上节中,我介绍了FlexBuilder4的10个新特性,同时我也强调了这
2023-06-17

Kubernetes1.5有哪些新特性

这篇“Kubernetes1.5有哪些新特性”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Kubernetes1.5有哪些新
2023-06-28

Android4.3新特性有哪些

Android 4.3(又名Jelly Bean)引入了以下一些新特性:1. 多用户支持:Android 4.3允许在同一设备上创建多个用户帐户,每个用户都有自己的个性化设置、应用和数据。2. 蓝牙低功耗(BLE):Android 4.3支
2023-09-25

FlexSDK4新特性有哪些

这篇文章主要介绍FlexSDK4新特性有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!FlexSDK4新特性FlexSDK4新特性一、主题在FlashBuilder4以前,Adobe默认的主题是Halo,而从Fl
2023-06-17

Flex4新特性有哪些

这篇文章将为大家详细讲解有关Flex4新特性有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Flex4新特性先来看看Flex4的一些消息吧:1.Flex4.0的代码编号为Spark,其有新的组件和皮肤
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录