ES13 中11个令人惊叹的 JavaScript 新特性
前言
与许多其他编程语言一样,JavaScript 也在不断发展。每年,该语言都会通过新功能变得更加强大,使开发人员能够编写更具表现力和简洁的代码。 小编今天就为大家介绍ES13中添加的最新功能,并查看其用法示例以更好地理解它们。
1.类
在ES13之前,类字段只能在构造函数中声明。与许多其他语言不同,无法在类的最外层作用域中声明或定义它们。
class Car {
constructor() {
this.color = 'blue';
this.age = 2;
}
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); //
而ES13 消除了这个限制。现在我们可以编写这样的代码:
class Car {
color = 'blue';
age = 2;
}const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2
2.私有方法和字段
ES13以前,不可能在类中声明私有成员。成员传统上带有下划线 ( _) 前缀,以表明它是私有的,但仍然可以从类外部访问和修改它。
class Person {
_firstName = 'Joseph';
_lastName = 'Stevens'; get name() {
return `${this._firstName} ${this._lastName}`;
}
}const person = new Person();
console.log(person.name); // Joseph Stevens
// 仍可以从类外部访问 // 原本打算设为私有的成员
console.log(person._firstName); // Joseph
console.log(person._lastName); // Stevens
// 也可以修改
person._firstName = 'Robert';
person._lastName = 'Becker';console.log(person.name); // Robert Becker
使用 ES13,我们现在可以通过在类前面添加 ( #) 来向类添加私有字段和成员。尝试从外部访问这些类将会引发错误:
class Person {
#firstName = 'Joseph';
#lastName = 'Stevens'; get name() {
return `${this.#firstName} ${this.#lastName}`;
}
}const person = new Person();
console.log(person.name);
// 语法错误:私有字段 '#firstName' 必须在一个外层类中声明
console.log(person.#firstName);
console.log(person.#lastName);
3.await顶层操作
在 JavaScript 中,await运算符用于暂停执行,直到 一个Promise被解决(执行或拒绝)。 以前只能在async中使用此运算符。不可以在全局作用域中直接使用await。
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
//语法错误:await 仅在异步函数中有效
await setTimeoutAsync(3000);
有了 ES13,现在我们可以:
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
// 等待超时 - 没有错误抛出
await setTimeoutAsync(3000);
4.静态类字段和静态私有方法
现在可以在 ES13 中为类声明静态字段和静态私有方法。静态方法可以使用关键字this访问类中的其他私有/公共静态成员,实例方法可以使用this.constructor访问他们。
class Person {
static #count = 0; static getCount() {
return this.#count;
} constructor() {
this.constructor.#incrementCount();
} static #incrementCount() {
this.#count++;
}
}const person1 = new Person();
const person2 = new Person();console.log(Person.getCount()); // 2
5.类静态块
ES13 引入了一项特性,允许开发者定义仅在创建类时执行一次的静态块。这一特性与其他面向对象编程语言(如 C# 和 Java)中的静态构造函数相似。
在一个类的主体中,你可以定义任意数量的静态 {} 初始化块。它们会按照声明的顺序与任何交错的静态字段初始值设定项一起执行。此外,你还可以通过块中的 super 关键字访问超类的静态属性。这为开发者提供了更多的灵活性和控制能力。
class Vehicle {
static defaultColor = 'blue';
}class Car extends Vehicle {
static colors = []; static {
this.colors.push(super.defaultColor, 'red');
} static {
this.colors.push('green');
}
}console.log(Car.colors); // [ 'blue', 'red', 'green' ]
6.检查对象中的私有字段
开发者如今可以利用这一新功能,使用运算符in来方便地检查对象是否包含某个特定的私有字段。
class Car {
#color; hasColor() {
return #color in this;
}
}const car = new Car();
console.log(car.hasColor()); // true;
通过运算符in,可以准确区分不同类中具有相同名称的私有字段。
class Car {
#color; hasColor() {
return #color in this;
}
}class House {
#color; hasColor() {
return #color in this;
}
}const car = new Car();
const house = new House();console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false
7.at() 索引方法
在 JavaScript 中,我们通常使用方括号[]来访问数组的第 t 个元素。这个过程非常简单,但实际上我们只是访问了索引为 t-1 的数组属性而已。
const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); // b
然而,当我们希望通过方括号来访问数组末尾的第 N 个元素时,我们需要使用索引 arr.length - N。
const arr = ['a', 'b', 'c', 'd'];
// 从末尾开始第一个元素
console.log(arr[arr.length - 1]); // d
// 倒数第二个元素 console.log
console.log(arr[arr.length - 2]); // c
借助全新的at()方法,可以以更加精简和富有表现力的方式来实现这一目标。要访问数组末尾的第N个元素,只需将负值-N作为参数传递给at()方法即可。
const arr = ['a', 'b', 'c', 'd'];
// 从末尾开始第一个元素
console.log(arr.at(-1)); // d
// 倒数第二个元素 console.log
console.log(arr.at(-2)); // c
除了数组之外,字符串和TypedArray对象现在也有at()方法。
const str = 'Coding Beauty';
console.log(str.at(-1)); // y
console.log(str.at(-2)); // tconst typedArray = new Uint8Array([16, 32, 48, 64]);
console.log(typedArray.at(-1)); // 64
console.log(typedArray.at(-2)); // 48
8.正则表达式匹配索引
在ES13之前,我们只能获取字符串中正则表达式匹配的起始索引,
const str = 'sun and moon';const regex = /and/;const matchObj = regex.exec(str);// [ 'and', index: 4, input: 'sun and moon', groups: undefined ]
console.log(matchObj);
使用ES13之后,可以通过指定一个/d正则表达式标志来获取匹配开始和结束的两个索引。这一特性赋予了更多的灵活性和控制能力。
const str = 'sun and moon';
const regex = /and/d;
const matchObj = regex.exec(str);
/**
[
'and',
index: 4,
input: 'sun and moon',
groups: undefined,
indices: [ [ 4, 7 ], groups: undefined ]
]
*/
console.log(matchObj);
设置标志后d,返回的对象将具有indices包含起始索引和结束索引的属性。
9.Object.hasOwn()方法
在 JavaScript 中,我们可以使用Object.prototype.hasOwnProperty()方法来检查对象是否具有给定的属性。
class Car {
color = 'green';
age = 2;
}const car = new Car();console.log(car.hasOwnProperty('age')); // true
console.log(car.hasOwnProperty('name')); // false
然而,这种方法存在一些问题。首先,Object.prototype.hasOwnProperty()方法并未受到保护,这意味着我们可以通过自定义的hasOwnProperty()方法来覆盖它,而这个自定义方法可能会具有与Object.prototype.hasOwnProperty()不同的行为。需要额外注意的是这一点。
class Car {
color = 'green';
age = 2; // This method does not tell us whether an object of
// this class has a given property.
hasOwnProperty() {
return false;
}
}const car = new Car();console.log(car.hasOwnProperty('age')); // false
console.log(car.hasOwnProperty('name')); // false
另外一个问题是,如果我们使用了 null 原型(通过 Object.create(null) 创建的对象),那么试图调用该方法将会产生错误。
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
// TypeError: obj.hasOwnProperty 不是函数
console.log(obj.hasOwnProperty('color'));
为了克服这些问题,我们可以利用属性调用方法Object.prototype.hasOwnProperty.call()来解决。具体示例如下所示:
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;console.log(Object.prototype.hasOwnProperty.call(obj, 'color')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); // false
这种方式并不十分便利。为了避免重复,我们可以编写一个可重用的函数,这样可以使我们的代码更加简洁和高效:
function objHasOwnProp(obj, propertyKey) {
return Object.prototype.hasOwnProperty.call(obj, propertyKey);
}const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;console.log(objHasOwnProp(obj, 'color')); // true
console.log(objHasOwnProp(obj, 'name')); // false
现在不需要在那样做了,我们还可以使用全新的内置方法Object.hasOwn()来处理这个问题。它与我们之前编写的可重用函数类似,接受对象和属性作为参数,并且返回一个布尔值,如果指定的属性是对象的直接属性,则返回true;否则返回false。
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;console.log(Object.hasOwn(obj, 'color')); // true
console.log(Object.hasOwn(obj, 'name')); // false
10.错误原因属性
现在,错误对象已经增加了一个cause属性,该属性用于指定导致错误抛出的原始错误。通过这种方式,我们可以为错误添加额外的上下文信息,从而更好地诊断意外的行为。要指定错误的原因,我们可以在作为构造函数的第二个参数传递给Error()的对象中设置属性来实现。这种方法能够提供更丰富的错误追踪和调试信息。
function userAction() {
try {
apiCallThatCanThrow();
} catch (err) {
throw new Error('New error message', { cause: err });
}
}try {
userAction();
} catch (err) {
console.log(err);
console.log(`Cause by: ${err.cause}`);
}
11.从数组最后查找
在 JavaScript 中,我们已经可以使用Array的find()方法来查找数组中满足指定测试条件的元素。类似地,我们也可以使用findIndex()方法来获取满足条件的元素的索引值。尽管find()和findIndex()都是从数组的第一个元素开始搜索,但在某些情况下,从最后一个元素开始搜索可能会更有效。
有些情况下,我们知道从数组的末尾进行查找可能会获得更好的性能表现。例如,在这里我们尝试查找数组中prop属性等于"value"的项目。这时候,可以通过使用reverse()方法将数组反转,然后使用find()和findIndex()方法来从末尾开始搜索。下面是具体的实现示例:
const letters = [
{ value: 'v' },
{ value: 'w' },
{ value: 'x' },
{ value: 'y' },
{ value: 'z' },
];const found = letters.find((item) => item.value === 'y');
const foundIndex = letters.findIndex((item) => item.value === 'y');console.log(found); // { value: 'y' }
console.log(foundIndex); // 3
上面的代码可以获取正确结果,但由于目标对象更接近数组的尾部,如果我们使用findLast()和findLastIndex()方法来从数组的末尾进行搜索,很可能能够显著提升程序的执行效率。通过这种方式,我们可以更快地找到所需的元素或索引,从而优化代码性能。
const letters = [
{ value: 'v' },
{ value: 'w' },
{ value: 'x' },
{ value: 'y' },
{ value: 'z' },
];const found = letters.findLast((item) => item.value === 'y');
const foundIndex = letters.findLastIndex((item) => item.value === 'y');console.log(found); // { value: 'y' }
console.log(foundIndex); // 3
在一些特定的使用场景中,我们可能需要从数组的末尾开始搜索来获取准确的元素。举个例子,假设我们要查找数字列表中的最后一个偶数,使用find()或findIndex()方法可能会导致错误的结果:
const nums = [7, 14, 3, 8, 10, 9];
// 给出 14,而不是 10
const lastEven = nums.find((value) => value % 2 === 0);
// 给出 1,而不是 4
const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);console.log(lastEven); // 14
console.log(lastEvenIndex); // 1
如果我们在调用reverse()方法之前使用数组的slice()方法创建新的数组副本,就可以避免不必要地改变原始数组的顺序。然而,在处理大型数组时,这种方法可能会导致性能问题,因为需要复制整个数组。
此外,findIndex()方法在反转数组时仍然无法达到预期效果,因为元素的反转会导致它们在原始数组中的索引改变。为了获取元素的原始索引,我们需要进行额外的计算,这意味着需要编写更多的代码来处理这种情况。
const nums = [7, 14, 3, 8, 10, 9];
// 在调用reverse()之前使用展开语法复制整个数组
// calling reverse()
const reversed = [...nums].reverse();
// 正确给出 10
const lastEven = reversed.find((value) => value % 2 === 0);
// 给出 1,而不是 4
const reversedIndex = reversed.findIndex((value) => value % 2 === 0);
// 需要重新计算得到原始索引
const lastEvenIndex = reversed.length - 1 - reversedIndex;console.log(lastEven); // 10
console.log(reversedIndex); // 1
console.log(lastEvenIndex); // 4
使用findLast()和findLastIndex()方法在需要查找数组中最后一个符合条件的元素或索引时非常实用。它们能够准确地定位目标对象,并且从数组末尾开始搜索,提供了高效的解决方案。
const nums = [7, 14, 3, 8, 10, 9];const lastEven = nums.findLast((num) => num % 2 === 0);
const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);console.log(lastEven); // 10
console.log(lastEvenIndex); // 4
结论
ES13 为 JavaScript 带来了一系列令人振奋的新功能,我们已经有幸见识了它们的魅力。通过运用这些功能,开发人员的工作效率将得到极大提升,同时也能以更加简洁、明晰的方式书写出更加纯净、精炼的代码。这些新特性为我们带来了更大的灵活性和便利性,使得我们的开发过程更加高效、愉悦。
原文链接:https://medium.com/coding-beauty/es13-javascript-features-eed7ed2f1497
扩展链接:
React + Springboot + Quartz,从0实现Excel报表自动化
ES13 中11个令人惊叹的 JavaScript 新特性的更多相关文章
- 返璞归真 asp.net mvc (11) - asp.net mvc 4.0 新特性之自宿主 Web API, 在 WebForm 中提供 Web API, 通过 Web API 上传文件, .net 4.5 带来的更方便的异步操作
原文:返璞归真 asp.net mvc (11) - asp.net mvc 4.0 新特性之自宿主 Web API, 在 WebForm 中提供 Web API, 通过 Web API 上传文件, ...
- 【广州.NET社区推荐】【译】Visual Studio 2019 中 WPF & UWP 的 XAML 开发工具新特性
原文 | Dmitry 翻译 | 郑子铭 自Visual Studio 2019推出以来,我们为使用WPF或UWP桌面应用程序的XAML开发人员发布了许多新功能.在本周的 Visual Studio ...
- ES6:JavaScript 新特性
我相信,在ECMAScript.next到来的时候,我们现在每天都在写的JavaScript代码将会发生巨大的变化.接下来的一年将会是令JavaScript开发者们兴奋的一年,越来越多的特性提案将被最 ...
- javascript新特性
让我们看看javascript中的一些新特性.本文将介绍它们的语法和相关链接,以帮助读者及时了解它们的进展.我们将通过编写一个小测试项目来演示如何快速使用这些新功能! 关于提案 提案分为五个阶段.有关 ...
- 7 个令人兴奋的 JavaScript 新特性
前言 一个ECMAScript标准的制作过程,包含了Stage 0到Stage 4五个阶段,每个阶段提交至下一阶段都需要TC39审批通过.本文介绍这些新特性处于Stage 3或者Stage 4阶段,这 ...
- oracle11g中SQL优化(SQL TUNING)新特性之SQL Plan Management(SPM)
1. 简介 Oracle Database11gR1引进了SQL PlanManagement(简称SPM),一套允许DBA捕获和保持任意SQL语句执行计划最优的新工具,这样,限制了刷新优化器统计 ...
- [译]C#8.0中一个使接口更加灵活的新特性-默认接口实现
9月份的时候,微软宣布正式发布C#8.0,作为.NET Core 3.0发行版的一部分.C#8.0的新特性之一就是默认接口实现.在本文中,我们将一起来聊聊默认接口实现. 众所周知,对现有应用程序的接口 ...
- 七种武器:JavaScript 新特性闪亮登场
JavaScript(或ECMA Script) 是一门不断发展的语言,有许多关于如何前进的建议和想法.TC39(技术委员会39)是负责定义JS标准和特性的委员会,今年他们非常活跃.以下是目前处于&q ...
- Oracle12c中SQL优化(SQL TUNING)新特性之SQL计划指令
SQL计划指令是Oracle12c中自适应查询优化的功能之一.SQL计划指令就像“额外的提醒” ,用以提醒优化器你先前选择了的计划并不是最优的,典型的是因为错误的势评估.错误的势评估往往是由统计信息缺 ...
- oracle11g中SQL优化(SQL TUNING)新特性之Adaptive Cursor Sharing (ACS)
1. ACS简介 Oracle Database 11g提供了Adaptive Cursor Sharing (ACS)功能,以克服以往不该共享的游标被共享的可能性.ACS使用两个新指标:sens ...
随机推荐
- 图灵丛书——GitHub入门
这是一篇关于我个人学习 GitHub 的笔记,主要是记录一些我认为比较重要的知识点,以及一些我认为比较好的学习资料. 学习书籍:GitHub 入门与实践(图灵程序设计丛书) 这本书的目录是这样的 第 ...
- 智慧饮水系统_Android客户端
智慧饮水系统(又名:水牛 APP) 1.介绍 该项目基于 Rfid-RC522.ESP-32 进行下位机开发,硬件模块 Rfid-RC522 主要读取用户的卡号,ESP32 单片机通过 WiFi 模块 ...
- ARC143
ARC143 考试情况:一眼订正,鉴定为做出前三题. A - Three Integers 以前做过 \(n\) 个数的版本,当时还被某人嘲讽说"堆,贪心,这都做不出来?". \( ...
- tar 命令压缩时报错 Removing leading `/' from member names 解决方法
原文:https://www.cnblogs.com/operationhome/p/9802554.html 在使用tar命令进行压缩打包的时候我们常常会遇到下面的错误.虽然它不会影响我们最后的压缩 ...
- tryhackme-OWASP
tryhackme-OWASP Top 10部分记录 敏感信息泄露 在assets目录中 可以看到到一个sqlite数据库的webapp.db文件 使用sqlite3 webapp.db .table ...
- OSPF 多区域配置实验
实验拓扑 实验需求 按照图示配置 IP 地址和loopback 接口 按照图示分区域配置 OSPF ,实现全网互通 为了路由结构稳定,要求路由器使用环回口作为 Router-id 在AR3上配置静默接 ...
- Python潮流周刊#6:Python 3.12 有我贡献的代码!
你好,我是猫哥.这里记录每周值得分享的 Python 及通用技术内容,部分为英文,已在小标题注明.(标题取自其中一则分享,不代表全部内容都是该主题,特此声明.) 首发于我的博客,https://pyt ...
- mysql_三大范式
介绍 数据库的三大范式就是数据库的表应该如何设计,应该注意什么. 第一范式 要求每一张表都有一个主键,每一个字段都不可再分. 举例: id username address 1 张三 中国,北京 2 ...
- ApacheSpark:HowtoBuildandDeployaRealtimeDataProcessinga
目录 2.1 基本概念解释 2.2 技术原理介绍 2.3 相关技术比较 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成与测试 4.1 应用场景介绍 4.2 应用实例分析 4. ...
- 自己动手实现rpc框架(一) 实现点对点的rpc通信
自己动手实现rpc框架(一) 实现点对点的rpc通信 1. 什么是rpc? RPC是远过程调用(Remote Procedure Call)的缩写形式,其区别于一个程序内部基本的过程调用(或者叫函数/ ...