ES13中5个最具变革性的JavaScript特性

前端岗位内推来了

ES13包含了许多有价值的特性,彻底改变了我们编写JavaScript的方式。

从异步升级到数组语法糖等等,让我们来看看这些特性,看看你是否错过了其中一些。

1. 顶级await

在ES13之前,我们永远不能在全局作用域中使用await

❌ 之前:

// X 语法错误:await 只在异步函数中有效
await setTimeoutAsync(3000);

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('codingbeautydev.com');
    }, timeout);
  });
}

我们总是必须将其放在async函数中或创建一个async IIFE(立即执行函数表达式):

// 异步立即执行函数
(async () => {
  await setTimeoutAsync(3000);
})();

// 类似 C++
async function main() {
  await setTimeoutAsync(3000);
}

✅ ES13之后:

// ✅ 等待超时 - 没有抛出错误
await setTimeoutAsync(3000);

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('codingbeautydev.com');
    }, timeout);
  });
}
2. 类声明升级

2.1 类字段声明

在ES13之前,我们只能在构造函数中声明类字段: 与许多其他语言不同,我们不能在类的最外层作用域中声明或定义它们。

❌ 之前:

✅ 现在有了ES13: 就像在TypeScript中一样:

2.2 私有方法和字段

在ES13之前,创建私有方法是不可能的。 我们还必须使用丑陋的下划线hack来表示私有性 — 但那只是一个指示。

❌ 之前:

class Person {
  _firstName = 'Tari';
  _lastName = 'Ibaba';

  get name() {
    return `${this._firstName} ${this._lastName}`;
  }
}

const person = new Person();
console.log(person.name); // Tari Ibaba

// 我们仍然可以访问私有成员!
console.log(person._firstName); // Tari
console.log(person._lastName); // Ibaba

// 它们也可以被修改!
person._firstName = 'Lionel';
person._lastName = 'Messi';

console.log(person.name); // Lionel Messi

✅ ES13之后:

我们可以通过在字段前加上井号(#)来为类添加私有字段和成员:

如果你试图从类外部访问它,你会得到一个语法错误:

class Person {
  #firstName = 'Tari';
  #lastName = 'Ibaba';

  get name() {
    return `${this.#firstName} ${this.#lastName}`;
  }
}

const person = new Person();
console.log(person.name);

// 语法错误:私有字段 '#firstName' 必须在封闭的类中声明
console.log(person.#firstName);
console.log(person.#lastName);

我们可以从错误消息中看到一些有趣的东西:

编译器甚至不期望你从类外部尝试访问私有字段 — 它假设你是在尝试创建一个。

2.3 静态类字段和静态私有方法

静态字段 — 类本身的属性,而不是任何特定实例的属性。

自ES13以来,我们现在可以轻松地为任何类创建它们:

class Person {
  static #count = 0;
  static eyeCount = 2;

  static getCount() {
    // 使用 this 访问同级静态成员
    return this.#count;
  }

  // 实例成员
  constructor() {
    // 使用 this.constructor 访问静态成员
    this.constructor.#incrementCount();
  }

  static #incrementCount() {
    this.#count++;
  }
}

const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2
3. 数组升级:新的at()方法

通常我们会使用方括号([])来访问数组的第N个元素。

const arr = ['a', 'b', 'c', 'd'];

console.log(arr[1]); // b

但从末尾访问第N个项目一直是一个痛点 -- 我们必须使用arr.length - N进行索引:

❌ ES13之前:

const arr = ['a', 'b', 'c', 'd'];

// 倒数第1个元素
console.log(arr[arr.length - 1]); // d

// 倒数第2个元素
console.log(arr[arr.length - 2]); // c

幸运的是,ES13带来了一个新的at()方法,解决了所有这些问题:

const str = 'Coding Beauty';

console.log(str.at(-1)); // y 倒数第1个字符

console.log(str.at(-2)); // t 倒数第2个字符
4. 静态类块

随着静态字段的出现,静态块也来了。 只在创建时执行一次代码 — 就像C#和Java等OOP语言中的静态构造函数。 所以你可以在类中创建任意多个静态块 — 所有代码都会按你定义的顺序运行:

class Vehicle {
  static defaultColor = 'blue';
}

class Car extends Vehicle {
  static colors = [];
  // 👇 pushes red before green
  // 👇 先添加 red,然后添加 green
  static {
    this.colors.push(super.defaultColor, 'red');
  }
  static {
    this.colors.push('green');
  }
}

console.log(Car.colors); // ['blue', 'red', 'green']
5. 错误报告升级

有时我们捕获调用栈下方方法的错误,只是为了将其重新抛出回调用栈上方。 但当我们这样做时,我们会失去原始错误中的关键信息:

try {
  userAction();
} catch (err) {
  // ❌ doesn't know fundamental cause of error
  // ❌ 不知道错误的根本原因
  console.log(err);
}

function userAction() {
  try {
    apiCallThatCanThrow();
  } catch (err) {
    // 👇 rethrow
    // 👇 重新抛出错误
    throw new Error('New error message');
  }
}

function apiCallThatCanThrow() {
  console.log('fetching from codingbeautydev.com...');
  throw new Error('throwing for no reason');
}

这就是为什么ES13引入了一个新的cause属性来保留这个重要信息并使调试更容易:

try {
  userAction();
} catch (err) {
  // ✅ now knows what caused the error
  // ✅ 现在知道了错误的原因
  console.log(err);
  console.log(`Caused by: ${err.cause}`);
}

function userAction() {
  try {
    apiCallThatCanThrow();
  } catch (err) {
    // ✅ error cause
    // ✅ 错误原因
    throw new Error('New error message', { cause: err });
  }
}

function apiCallThatCanThrow() {
  console.log('fetching from codingbeautydev.com...');
  throw new Error('throwing for no reason');
}

最后的思考

总的来说,ES13对JavaScript来说是一个重大飞跃,它带来了几个已成为现代开发必不可少的特性。 使你能够编写更清晰、更简洁、更具表现力的代码。

最后:

CSS技巧与案例详解

vue2与vue3技巧合集

VueUse源码解读

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@大迁世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值