盘点2022年ECMAScript新特性(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. 给类添加私有方法和成员变量:

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出现后我们只需要在成员变量前面加上一个hashtag(#)前缀就可以使这个属性变成了一个私有的属性在外界访问这个属性的时候是会报错的

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

我们都知道在js中,await操作符是promise接收成功的一个语法糖,他可以暂停代码必须等到这个promise有了结果以后(settled(fulfilled或者rejected))代码才能继续往下执行,而且await必须搭配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);
  });
}

// SyntaxError: await is only valid in async functions
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.使用in来判断某个对象是否拥有私有属性

这个新属性的名字其实叫做Ergonomic Brand Checks for Private Fields 大概意思就是它就是来判断某个对象拥有某个特定的私有属性 可以通过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操作符来索引元素

一般在数组中我们想要访问第N个元素,我们会这样写 [ N-1]来进行访问这个元素

const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); //b

这样写是没有问题的,其他的很多语言也会这样写 但是当你去访问倒数第几个元素的时候就显的很奇怪

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

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

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

这样会让代码看的很繁琐 es13中有一个at操作符可以解决这个问题而且可以让我们来进行更优雅的写代码当你去访问倒数第N个元素的时候只需要传入at(-N)即可

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

// 倒数第一个元素
console.log(arr.at(-1)); // d
// 倒数第二个元素
console.log(arr.at(-2)); // c

​

这样写代码就会感觉很通俗易懂 另外string和TypedArray也支持

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在返回match对象的时候,给我们返回匹配到的子字符串的开始和结束索引。

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()方法

在JS中,我们可以使用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

上面这个办法是不受保护的 他可以被类中的hasOwnProperty()覆盖掉,而自定义方法做的事情可能和Object.prototype.hasOwnProperty()做的事情完全不一样:

class Car {
  color = 'green';
  age = 2;
  
  // 你看这个方法就没有告诉我们这个类的对象是不是有某个属性
  hasOwnProperty() {
    return false;
  }
}

const car = new Car();

console.log(car.hasOwnProperty('age')); // false
console.log(car.hasOwnProperty('name')); // false

上面的写法第二个问题就是:当一个对象是通过Object.create(null)创建出来的具有null原型的对象时,你想在这个对象上面调用hasOwnProperty这个方法是会报错的:

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这个Functioncall方法:

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

Object.prototype.hasOwnProperty.call(obj, 'color')

当然我们也可以来进行一些简单的封装来进行代码的优化和美观

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

封装是封装了,不过看着好麻烦有木有?所以ES13诞生了一个全新的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.Error对象的Cause属性

ES13后,Error对象多了一个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.数组支持逆顺序查找

虽然这个不怎么常用,但是假如当我们知道一个元素在比较靠后的位置的时候可以使用这个来你顺序查找再碰见比较复杂的数据的时候可以适当的提升代码的性能

const letters = [
  { value: 'v' },
  { value: 'w' },
  { value: 'x' },
  { value: 'y' },
  { value: 'z' },
];

// 我们想要找的y元素比较靠后, 顺序查找性能不好
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

这种情况下 find()findIndex()都可以实现这种效果,但是就是性能比较差点

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值