ES新特性之class关键字

大家好,我是一碗周,一个不想被喝(内卷)的前端。如果写的文章有幸可以得到你的青睐,万分有幸~

类的声明

类是什么

ECMAScript6提供了更接近传统开发语言的手法,引入了类(Class)的概念。类作为对象的模板,在JavaScript中只是一个语法糖。

class关键字只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

示例代码如下:

// ES 5 中定义对象的方式
// 定义一个构造函数
const Hero1 = function () {
  this.name = 'ywanzhou',
    this.print = () => {
      console.log('this is ywanzhou');
    }
}
// 通过构造函数创建对象
const hero1 = new Hero1();
console.log(hero1.name); // ywanzhou

// 通过 ES6 的方式定义构造函数
class Hero2 {
  // 构造器
  constructor() {
    this.name = 'ywanzhou',
      this.print = () => {
        console.log('this is ywanzhou');
      }
  }
}
// 通过类创建对象
const hero2 = new Hero2();
console.log(hero2.name); // ywanzhou

上面的代码仅供参考,会在下面进行讲解

类的声明

类的声明具有两种方式:

第一种是类的声明方式,语法结构如下所示:

class name [extends] {
  // class body
}

参数说明:

  • name:表示类名

  • extends:可选,用于类的继承

使用类的声明方式声明类是不允许再次声明已经存在的类的,否则会抛出一个异常。

示例代码如下所示:

// 类的声明方式
class Hero {
  constructor() {
    this.print = () => {
      console.log('this is Hero');
    }
  }
}
// 如果声明已经存在的类会抛出异常
// class Hero {} // SyntaxError: Identifier 'Hero' has already been declared
const hero = new Hero()
hero.print() // this is Hero

第二种是类的表达式方式,语法结构如下所示:

const MyClassName = class [className] [extends] {
  // class body
}

参数说明:

  • MyClassNmae:用于后面代码逻辑调用的类名

  • className:用于当前类的内部使用

  • extends:可选,用于类的继承

和函数表达式相同的一点是,类表达式可以是命名也可以是匿名的。如果是命名类表达式,这个名字只能在类体内部才能访问到。

示例代码如下所示:

// 类的表达式方式
const Hero = class heros {
  /*
   * Hero 用于后面代码逻辑
   * heros 用于当前类中
   */
  constructor() {
    this.print = () => {
      console.log('this is Hero');
    }
  }
}
// 创建对象
const hero = new Hero();
hero.print() // this is Hero

构造函数

构造函数/构造器(Constructor)是用于创建和初始化类中创建的一个对象的一种特殊方法。

语法结构如下所示:

constructor([arguments]) { ... }

参数arguments表示传入的形参,实参是创建类的时候传入的。

在一个类中只能有一个名为constructor的特殊方法。一个类中出现多次构造函数(constructor)方法将会抛出一个SyntaxError错误。

在一个构造方法中可以使用super关键字来调用一个父类的构造方法。

如果没有显式指定构造方法,则会添加默认的constructor方法。

如果不指定一个构造函数(constructor)方法,则使用一个默认的构造函数(constructor)。

注意事项

  1. 在类的内部,默认就是严格模式,所以不需要手动开启严格模式

  2. 类不存在声明提前,这一点与ES5完全不同。

  3. 声明类时,是不存在重复声明的。如果一个类被重复声明的话,则引起解析错误。

静态方法

什么是静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为静态方法

静态方法的语法

static关键字为一个类定义了一个静态方法。静态方法不会在类的实例上被调用,相反被类本身调用。语法结构如下所示:

static methodName() { ... }

参数methodName表示指定类中的静态方法名称。

示例代码如下所示:

class Hero {
  constructor() {
    this.name = 'ywanzhou'
  }
  // 声明一个静态方法
  static method() {
    console.log('这是一个静态方法');
  }
}

静态方法的调用

静态方法的调用是直接在类上进行,不能再类的实例上进行调用。示例代码如下所示:

class Hero {
  constructor() {
    this.name = 'ywanzhou'
  }
  // 声明一个静态方法
  static method() {
    console.log('这是一个静态方法');
  }
}
const hero = new Hero()
// 通过实例来调用静态方法
// hero.method() // 抛出异常 TypeError: hero.method is not a function
// 通过类的调用静态方法
Hero.method() // 这是一个静态方法

从另一个静态方法调用静态方法的时候,可以使用this关键字,测试代码如下所示:

class Hero {
  constructor() {
    this.name = 'ywanzhou'
  }
  // 声明一个静态方法
  static method1() {
    console.log('这是一个静态方法');
  }
  static method2() {
    // 通过 this 调用静态方法
    this.method1()
  }
}
Hero.method2() // 这是一个静态方法

从类的构造函数和其他方法中调用是不能使用this关键字来访问的。需要使用类名来调用,或者通过构造函数的属性来调用该方法,示例代码如下所示:

class Hero {
  constructor() {
    this.name = 'ywanzhou'
    Hero.method1(); // 通过类名调用
    this.constructor.method1() // 通过构造函数的属性来调用
  }
  // 声明一个静态方法
  static method1() {
    console.log('这是一个静态方法');
  }
}
const hero = new Hero() // 这是一个静态方法 * 2

类的继承

实现类的继承

detends关键字用于类声明或者类表达式中,以创建一个类,该类作为另一个类子类。语法结构如下所示:

class ChildClass extends ParentClass {...}

extends关键字用来创建一个普通类或者内建对象的子类。

值得注意的是,继承的.prototype必须是一个Object或者null

实现继承的代码如下所示:

// 定义一个父类
class Parent {
  constructor(name) {
    this.name = name
  }
  // 普通方法
  print() {
    console.log(this.name);
  }
}
// 定义子类,继承于父类
class Child extends Parent {
  constructor(name, age) {
    // 代表父类的构造函数
    super(name)
    this.age = age
  }
  prints() {
    console.log(this.name, this.age);
  }
}
// 实例化子类
const child = new Child('ywanzhou', 18)
// 调用父类方法
child.print(); // ywanzhou
// 调用子类方法
child.prints(); // ywanzhou 18

继承于内置对象

JavaScript中的内置对象也是可以继承的,例如Date对象。示例代码如下所示:

class myDate extends Date {
  constructor() {
    super()
    // 定义一个返回当前日期的方法
    this.getFormattedDate = () => {
      return `${this.getFullYear()}-${this.getMonth()}-${this.getDate()}`
    }
  }
}
const my_date = new myDate();
console.log(my_date.getFormattedDate()); // 2020-11-26

super关键

super关键字,既可以当做函数使用,也可以当做对象使用。在这两种情况下,他的用法完全不同。

super关键字作为函数调用时,代表父类的构造函数。ECMAScript6要求子类的构造函数必须执行一次super函数。
示例代码如下所示:
值得注意的是,super虽然代表父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)

class A {}; // 父类

// 子类继承父类
class B extends A {
  constructor() {
    super()
  }
}

super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中指向父类。
值得注意的是,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过 super调用的。

class A {
  p() {
    return 2
  }
}
class B extends A {
  constructor() {
    super()
    console.log(super.p()); // 2
  }
}
const b = new B()

总结

在ECMAScript6中新增了类的概念,并增加了一个class关键字,但实际上ES6中的类仅仅是一个语法糖,JavaScript中创建对象始终无法脱离原型链这个概念。

但是在ES6中添加了类的这个概念之后,在JS中编写类方便了也简单了许多。

往期推荐

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一碗周.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值