尝试ES13的新特性

127 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

类的声明

ES6中引入了Class这个概念,可以通过关键字class定义一个类

class Person{
    constructor(name,age){
         this.name = name;
         this.age = age;
    }
    show(){
        console.log(`name为${this.name}-age为${this.age}`)
    }
}

const person = new Person("李四",11)
person.show()

而在ES13中出现比这种更加简洁的写法,让我们一起来看一看

以前我们要定义类字段必须要在constructor方法中声明,现在我们可以在顶层声明

class Person{
    name = "张三";
    age = 11;
}
const person = new Person()
console.log(person.name) // 张三

同时这种方式定义的属性可作为一个公共属性,即类可以直接调用,实例也可以调用

class Person{
     name = "张三";
    age = 11;
    constructor(grade){
         this.grade = grade;
    }
    
}
// console.log(Person.#name)
const person = new Person("3年级")
//类不可以直接调用在constructor中定义的属性
console.log(Person.grade); // undefined
console.log(Person.name) // 张三
console.log(person.grade)//3年级
console.log(person.name);//张三

私有属性

使用#为类添加私有属性


class Person{
    #name = "张三";
    age = 11;
    
}
const person = new Person()
console.log(person.name)//undefined
console.log(person.#name)//这里会提示一个语法错误

私有类属性

通过static和 # 添加一个类属性

class Person{
    static #name = "张三";
    age = 11;
    
}
console.log(Person.name)//undefined

静态代码块

在加载类就执行一次的静态代码块

class Person {
    static name = "张三";
    static  age = 11;
    constructor(grade) {
        this.grade = grade;
        console.log("grade", this.grade) // 3年级
    }
    static {
        console.log("name", this.name) // 张三
    }
    static {
         console.log("age",this.age) // 11
    }
    #show() {
        console.log(this.grade) 
    }

}
// console.log(Person.#name)
const person = new Person("3年级")

且执行顺序先于constructor执行,多个静态代码块按顺序执行

in运算符

in运算符可以用于检查指定的属性或者字段在对应的对象或者类中,是则返回true,反之为false

class Person {
    #name = "张三";
    age = 11;
    constructor(grade) {
        this.grade = grade;
    }
    hasAge() {
        return "age" in this
    }
    hasName() {
        return #name in this
    }


}
const person = new Person("3年级")
console.log(person.hasAge());// true
console.log(person.hasName());// true

可以看见。类私有属性照样可以检测。同时可以区分出不同类的同名字段

class Person {
    #name = "张三";
    age = 11;
    hasName() {
        // console.log(this.#name)
        return #name in this
    }
}
class Person1{
    #name = "李四"
    hasName(){
        //  console.log(this.#name);
         return #name in this
    }
}
const person = new Person()
const person1 = new Person1()
console.log(person.hasName()); //true
console.log(person.hasName.call(person1)) // false
console.log(person1.hasName()) // true

at()方法

在正常情况下,我们需要访问数组其中的某一项,一般是这样数组名[索引],这里我们只能访问数组的n-1个数组成员,访问索引之外的就会返回undefined,如:

const arr = [1,2,3]
console.log(arr[1]); // 2
console.log(arr[-1]) // undefined

如果这里我们使用at()方法就会有不一样的表现力.

const arr = [1,2,3]
console.log(arr[1]); // 2
console.log(arr[-1]) // undefined
console.log(arr.at(-1)); // 3

可以看见,不仅取出来力,而且刚好是倒数第一个数,再试试-2

console.log(arr.at(-2)); //2

得出一个结论:这样的传入的是一个大于等于0的数,那么和直接访问没有区别,如传入的是一个负数,访问的就是索引为 length + n (n是参数)的数,也可以理解为访问的是倒数第n个元素。除数组外,字符串和TypeArray也有同样的方法。

await运算符

ES2017中加入新的语法糖就是async/await,用此来简化Promise的使用,await运算符用于暂定执行,直到Promise被完成(成功或者失败皆可)。以前我们只能用await只能在async声明过的函数中使用,要不然就会报错,如:

function getName() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("张三")
        }, 1000)
    })
}
let name;
const setName = async () => {
    name = await getName();
    console.log("前面的", name);
}
setName()
await getName()//await is only valid in async functions and the top level bodies of modules

要想解决这个问题,其中一个的解决方案就是开启顶层await,需要注意的是顶层await只在ES模块中生效,如果在node环境下,需要在package.json中显示开启"type":"module",这段代码可以看出效果:


function getName() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("张三")
        }, 1000)
    })
}
let name;
const setName = async () => {
    name = await getName();
    console.log("前面的", name); // 前面的 张三
}
setName()
const nextName = await getName()
console.log("后面的",nextName); // 后面的 张三

RegExp匹配索引

exec可以帮助我们获取到给定字符串匹配到RegExp对象中的起始索引。如:

const str = "这是一个新的特性"
const reg = new RegExp("新的");

const exec = reg.exec(str);
console.log(exec);//[ '新的', index: 4, input: '这是一个新的特性', groups: undefined ]

index就是它的起始索引。我们可以在RegExp的第二个参数加一个d,可以得到匹配字符串的起始和结束索引。如:

const str = "这是一个新的特性"
const reg = new RegExp("新的","d");

const exec = reg.exec(str);
console.log(exec);//[
  '新的',
  index: 4,
  input: '这是一个新的特性',
  groups: undefined,
  indices: [ [ 4, 6 ], groups: undefined ]
]

indices数组的第一个成员就是起始和结束索引的数组。

Object.hasOwn()方法

在这个新特性出来之前,我们是使用Object.prototype.hasOwnProperty()方法来检测对象中是否含有特定的属性。 因为该方法在Object的原型对象上,我们完全可以重新修改或者定义一个新的该方法,并且覆盖掉它,使其与不一样的行为。

解决这个问题的其中一个方案就是使用Object.hasOwn()方法,该方法是直接定义在Object的静态方法。该方法接受对象属性作为参数。如果对象中包含了属性就返回true,反之为false。如:

const obj = {
    title:"这是一个新的特性"
}
console.log(Object.hasOwn(obj,"title"));// true

错误原因

使用throw new Error可以通过第二个参数加入cause属性来指定错误原因。这里就是简单模拟一下,具体场景会更加复杂。

function cause() {
        throw new Error("这是一个错误", { cause: "使用cause" })
}

try {
    cause()
} catch (error) {
    console.log(error);
    console.log(error.cause) // 使用cause
}

end

瑞思拜