共计 8484 个字符,预计需要花费 22 分钟才能阅读完成。
前言
与许多其余编程语言一样,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-eed…
扩大链接:
高级 SQL 剖析函数 - 如何用窗口函数进行排名计算
3D 模型 +BI 剖析,打造全新的交互式 3D 可视化大屏开发计划
React + Springboot + Quartz,从 0 实现 Excel 报表自动化