11 个 ES2022(ES13)中惊人的 JavaScript 新特性

简介: 与许多其他编程语言一样,JavaScript 也在不断发展,每年,该语言都会通过新功能变得更强大,让开发人员编写更具表现力和简洁的代码。

与许多其他编程语言一样,JavaScript 也在不断发展,每年,该语言都会通过新功能变得更强大,让开发人员编写更具表现力和简洁的代码。
让我们探索 ECMAScript 2022 (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); // 2
ES13 消除了这个限制,现在我们可以编写如下代码:

class Car {
color = 'blue';
age = 2;
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2
2、私有方法和字段

以前,不能在类中声明私有成员,成员通常以下划线 (_) 为前缀,表示它是私有的,但仍然可以从类外部访问和修改。

class Person {
_firstName = 'Joseph';
_lastName = 'Stevens';
get name() {

return `${this._firstName} ${this._lastName}`;

}
}
const person = new Person();
console.log(person.name); // Joseph Stevens
// Members intended to be private can still be accessed
// from outside the class
console.log(person._firstName); // Joseph
console.log(person._lastName); // Stevens
// They can also be modified
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);
// SyntaxError: Private field '#firstName' must be
// declared in an enclosing class
console.log(person.#firstName);
console.log(person.#lastName);
请注意,这里抛出的错误是语法错误,发生在编译时,因此没有部分代码运行,编译器甚至不希望您尝试从类外部访问私有字段,因此,它假定您正在尝试声明一个。

3、await运算符

在 JavaScript 中,await 运算符用于暂停执行,直到 Promise 被解决(履行或拒绝)。

以前,我们只能在 async 函数中使用此运算符 - 使用 async 关键字声明的函数。我们无法在全球范围内这样做。

function setTimeoutAsync(timeout) {
return new Promise((resolve) => {

setTimeout(() => {
  resolve();
}, timeout);

});
}
// SyntaxError: await is only valid in async functions
await setTimeoutAsync(3000);
使用 ES13,现在我们可以:

function setTimeoutAsync(timeout) {
return new Promise((resolve) => {

setTimeout(() => {
  resolve();
}, timeout);

});
}
// Waits for timeout - no error thrown
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)中的静态构造函数。

一个类的类主体中可以有任意数量的静态 {} 初始化块,它们将与任何交错的静态字段初始值设定项一起按照声明的顺序执行,我们可以在静态块中使用超属性来访问超类的属性。

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 中使用方括号 ([]) 来访问数组的第 N 个元素,这通常是一个简单的过程,我们只访问数组的 N - 1 属性。

const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); // b
但是,如果我们想使用方括号访问数组末尾的第 N 个项目,我们必须使用 arr.length - N 的索引。

const arr = ['a', 'b', 'c', 'd'];
// 1st element from the end
console.log(arr[arr.length - 1]); // d
// 2nd element from the end
console.log(arr[arr.length - 2]); // c
新的 at() 方法让我们可以更简洁、更有表现力地做到这一点,要访问数组末尾的第 N 个元素,我们只需将负值 -N 传递给 at()。

const arr = ['a', 'b', 'c', 'd'];
// 1st element from the end
console.log(arr.at(-1)); // d
// 2nd element from the end
console.log(arr.at(-2)); // c
除了数组,字符串和 TypedArray 对象现在也有 at() 方法。

const str = 'Coding Beauty';
console.log(str.at(-1)); // y
console.log(str.at(-2)); // t
const typedArray = new Uint8Array([16, 32, 48, 64]);
console.log(typedArray.at(-1)); // 64
console.log(typedArray.at(-2)); // 48
8、 RegExp 匹配索引

这个新功能允许我们指定我们想要获取给定字符串中 RegExp 对象匹配的开始和结束索引。

以前,我们只能在字符串中获取正则表达式匹配的起始索引。

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);
我们现在可以指定一个 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 is not a function
console.log(obj.hasOwnProperty('color'));
解决这些问题的一种方法是使用调用 Object.prototype.hasOwnProperty Function 属性上的 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() 构造函数的对象上设置 cause 属性来指定错误的原因。

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 等于 y 的项目。使用 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];
// gives 14, instead of 10
const lastEven = nums.find((value) => value % 2 === 0);
// gives 1, instead of 4
const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);
console.log(lastEven); // 14
console.log(lastEvenIndex); // 1
我们可以在调用 find() 和 findIndex() 之前调用数组的 reverse() 方法来反转元素的顺序。

但是这种方法会导致数组发生不必要的突变,因为 reverse() 会反转数组的元素。避免这种突变的唯一方法是制作整个数组的新副本,这可能会导致大型数组出现性能问题。

此外, findIndex() 仍然无法在反转数组上工作,因为反转元素也意味着更改它们在原始数组中的索引。要获得原始索引,我们需要执行额外的计算,这意味着编写更多代码。

const nums = [7, 14, 3, 8, 10, 9];
// Copying the entire array with the spread syntax before
// calling reverse()
const reversed = [...nums].reverse();
// correctly gives 10
const lastEven = reversed.find((value) => value % 2 === 0);
// gives 1, instead of 4
const reversedIndex = reversed.findIndex((value) => value % 2 === 0);
// Need to re-calculate to get original index
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 带来的最新特性,使用它们来提高我们作为开发人员的工作效率,并以更简洁和清晰的方式编写更简洁的代码。如果你觉得我这篇文章对你有用的话,请记得点赞我,关注我,并将它分享给你身边的朋友,也许能够帮助到他。

最后,感谢你的阅读。

相关文章
|
20天前
|
JavaScript 前端开发 编译器
掌握现代化JavaScript:ECMAScript提案与特性
【10月更文挑战第13天】本文介绍了ECMAScript(ES)的最新提案与特性,包括可选链、空值合并运算符、类字段和顶层Await等。通过跟踪TC39提案、使用Babel或TypeScript、测试兼容性以及逐步迁移,开发者可以高效地采用这些新特性,简化代码、提高开发效率并增强应用功能。文章还提供了实战技巧,帮助开发者在现代Web开发中充分利用这些现代化的特性。
|
23天前
|
JavaScript 前端开发 索引
JavaScript ES6及后续版本:新增的常用特性与亮点解析
JavaScript ES6及后续版本:新增的常用特性与亮点解析
21 4
|
6天前
|
前端开发 JavaScript
JavaScript新纪元:ES6+特性深度解析与实战应用
【10月更文挑战第29天】本文深入解析ES6+的核心特性,包括箭头函数、模板字符串、解构赋值、Promise、模块化和类等,结合实战应用,展示如何利用这些新特性编写更加高效和优雅的代码。
16 0
|
2月前
|
JavaScript 前端开发 Oracle
软件工程师,学习下JavaScript ES6新特性吧
软件工程师,学习下JavaScript ES6新特性吧
42 9
|
3月前
|
Rust JavaScript 前端开发
Rust! 无VDom! 尤雨溪解析 Vue.js 2024 新特性
Rust! 无VDom! 尤雨溪解析 Vue.js 2024 新特性
|
3月前
|
Web App开发 前端开发 JavaScript
[译] JavaScript ES2021 中激动人心的特性
[译] JavaScript ES2021 中激动人心的特性
|
3月前
|
前端开发 JavaScript 开发者
翻天覆地!ES6+新特性大爆发,揭秘JavaScript代码的惊人蜕变!
【8月更文挑战第27天】自ES6标准发布以来,JavaScript新增的特性极大地提升了编程效率并简化了代码。本文重点介绍了五大特性:函数默认参数简化、模板字符串的强大功能、解构赋值的便捷性、箭头函数的简洁之美。这些特性不仅使代码更加简洁、易读,还解决了传统写法中的诸多问题。通过学习和应用这些新特性,开发者可以编写出更高效、更优雅的代码,以应对日益复杂的编程挑战。
63 2
|
3月前
|
JavaScript 前端开发 安全
JS 混淆解析:JS 压缩混淆原理、OB 混淆特性、OB 混淆JS、混淆突破实战
JS 混淆解析:JS 压缩混淆原理、OB 混淆特性、OB 混淆JS、混淆突破实战
144 2
|
3月前
|
JavaScript 前端开发 API
JavaScript特性检测
JavaScript特性检测
|
3月前
|
开发者 图形学 C#
深度解密:Unity游戏开发中的动画艺术——Mecanim状态机如何让游戏角色栩栩如生:从基础设置到高级状态切换的全面指南,助你打造流畅自然的游戏动画体验
【8月更文挑战第31天】Unity动画系统是游戏开发的关键部分,尤其适用于复杂角色动画。本文通过具体案例讲解Mecanim动画状态机的使用方法及原理。我们创建一个游戏角色并设计行走、奔跑和攻击动画,详细介绍动画状态机设置及脚本控制。首先导入动画资源并添加Animator组件,然后创建Animator Controller并设置状态间的转换条件。通过编写C#脚本(如PlayerMovement)控制动画状态切换,实现基于玩家输入的动画过渡。此方法不仅适用于游戏角色,还可用于任何需动态动画响应的对象,增强游戏的真实感与互动性。
88 0