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 ...
随机推荐
- R 语言中的高级图像处理包
最新的 magick 包是为能够在 R 中更现代化.简单化高质量图像处理而进行的一次努力.该包封装了目前最强大的开源图片处理库 ImageMagick STL . ImageMagick 库具有大量功 ...
- 一分钟学一个 Linux 命令 - mkdir 和 touch
前言 大家好,我是god23bin.欢迎来到<一分钟学一个 Linux 命令>系列,今天需要你花两分钟时间来学习下,因为今天要讲的是两个命令,mkdir 和 touch 命令.前一个命令是 ...
- vue3实现H5网页录音并上传(mp3、wav)兼容Android、iOS和PC端
使用 Recorder插件 可以在HTML5网页中进行录音,录音完成后得到blob文件对象,然后将blob上传到服务器:项目使用的vue3.0版本(这个插件同时支持vue2.0.也支持uniapp,很 ...
- 使用Docker将Vite Vue项目部署到Nginx二级目录
Vue项目配置 使用Vite创建一个Vue项目,点我查看如何创建 配置打包路径 在Nginx中如果是二级目录,例如/web时,需要设置线上的打包路径 在项目跟路径下创建两个文件:.env.produc ...
- CF1034D Intervals of Intervals
简要题意 给定 \(n\) 个区间组成的序列,定义它的一个连续段的价值为这个段内所有区间的并覆盖的长度.求价值前 \(k\) 大的段的价值和. 数据范围:\(1\le n\le 3\times 10^ ...
- 如何让一句话木马绕过waf ?
一.什么是一句话木马? 一句话木马就是只需要一行代码的木马,短短一行代码,就能做到和大马相当的功能.为了绕过waf的检测,一句话木马出现了无数中变形,但本质是不变的:木马的函数执行了我们发送的命令. ...
- 龙芯电脑编译redis (loongarch)
1.获取源码 源码地址:https://redis.io/download/#redis-downloads 最新版本是7.2,这里用redis5测试,最后一个版本是5.0.14 wget https ...
- 4.2 针对PE文件的扫描
通过运用LyScript插件并配合pefile模块,即可实现对特定PE文件的扫描功能,例如载入PE程序到内存,验证PE启用的保护方式,计算PE节区内存特征,文件FOA与内存VA转换等功能的实现,首先简 ...
- 如何将Maven项目快速改造成一个java web项目(方式二)
原始的maven项目,使用IDEA打开后,目录结构如下所示 删除pom.xml文件,删除resource目录,将java目录下的代码放到项目根目录下, 将webapp目录放到项目根目录下.如下图所示 ...
- React: 动态添加样式
问题背景 在软件开发过程中,经常会出现动态添加style或className,比如:同一个表格组件在A处调用,需要固定前四列数据, B处调用则不用,那这时候,动态添加元素就派上了用场. 解决方案 如下 ...