[JavaScript] 探索 ES6 类语法 - 类声明、初始化、方法定义、继承等

JavaScript 的类在 ES6(ES2015) 时期新推出的语法特性。在此之前,JavaScript 主要通过函数和原型来实现面向对象编程。类的出现,让面向对象编程更加直观与清晰。

为何使用类及其优势

  • 直观性:类的语法与其他面向对象语言的类结构类似,为开发者提供了熟悉且易于理解的体验。
  • 可重用性:通过类与继承,可以显著提升代码的复用性。
  • 模块化:代码结构更有条理,便于管理。

基础语法

类的声明

在 JavaScript 中,类是通过 class 关键字来声明的。

javascript
class Person {}

使用构造函数进行初始化

constructor 是一个特殊的方法,用于创建和初始化一个类中所创建的对象。该方法可以初始化对象的状态。

javascript
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

在上述代码中,Person 类具有姓名和年龄两个属性。使用 new 关键字创建这个类的实例时,传递的姓名和年龄会被设置到该实例中。

javascript
const ming = new Person('小明', 25);
console.log(ming.name);  // 小明

方法定义

在类中,可以定义函数作为类的方法。这些方法可以在类的实例中调用。

javascript
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`我是${this.name},今年${this.age}岁。`);
  }
}

实例方法与静态方法

  • 实例方法:在类的实例中调用的方法,如上面的 introduce 方法。
  • 静态方法:使用 static 关键字定义,并在类本身调用,无需创建实例即可使用。

javascript
class Person {
  static populationCount() {
    console.log('全球人口数十亿。');
  }
}
Person.populationCount();  // 全球人口数十亿。

静态方法 populationCount 可以直接通过类名调用,无需创建实例。

javascript
Person.populationCount();  // 全球人口数十亿。

继承与拓展

在 JavaScript 中,类的继承是一种机制,允许将已有类的属性和方法传递给新类。这有助于增强代码的复用性和建立类之间的关系。

继承概念

在 JavaScript 中,类的继承是通过 extends 关键字实现的。

javascript
class Animal {
 sound() {
    console.log('动物发出的声音');
  }
}

class Dog extends Animal {

}

通过继承,子类会继承父类的所有属性和方法。在上述示例中,Dog 类继承了 Animal 类的所有方法和属性。

利用继承提高代码复用性

通过继承,可以在父类中定义共通的逻辑或数据结构,并在子类中只添加特定功能或属性,这有助于减少代码的重复,提高开发效率和维护性。

方法覆盖

在子类中,可以重新定义父类中的方法。这称为方法覆盖。被覆盖的方法会取代父类中的原有方法。

javascript
class Animal {
  sound() {
    console.log('动物发出的声音');
  }
}

class Dog extends Animal {
  sound() {
    console.log('汪汪');
  }
}

const puppy = new Dog();
puppy.sound();  // 汪汪

使用 Super 关键字

当在子类中需要调用父类的同名方法时,可以使用 super 关键字。

javascript
class Animal {
  sound() {
    console.log('动物发出的声音');
  }
}

class Dog extends Animal {
  sound() {
    super.sound();
    console.log('汪汪');
  }
}

const puppy = new Dog();
puppy.sound();  // 动物发出的声音  汪汪

构造函数重写

在子类中,可以重写父类的构造函数。但若在子类的构造函数未调用super,则会导致错误。

通过super关键字于子类的构造函数,能调用父类的构造函数,进行必要的初始化。

javascript
class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
}

const puppy = new Dog('小狗', '贵宾犬');
console.log(puppy.name);   // 小狗
console.log(puppy.breed); // 贵宾犬

访问修饰符

在JavaScript类中,为了限制数据和方法的访问权限,需要使用访问修饰符。

Public, Private, Protected

访问修饰符用于指定类成员(属性和方法)的访问权限。通过此,可以实现类的内部逻辑隐藏,或对某些成员实施访问限制,确保面向对象的封装原则得到维护。

  • Public:默认成员皆为公共,可在任何位置访问。
  • Private:以#或下划线(_)起始的成员为私有,仅可在该类内访问。
  • Protected:尽管JavaScript暂无官方的受保护修饰符,但下划线(_)常被视为受保护成员。该成员可以在该类或其子类中访问。

用下划线(_)和#标识私有成员变量与方法

javascript
class 示例 {
  __protectedMember = "此为受保护成员。";
  #privateMember = "此为私有变量。";

  _protectedMethod() {
    console.log("此为受保护方法。");
  }

  #privateMethod() {
    console.log("此为私有方法。");
  }
}

Getter与Setter方法

Getter与Setter方法用于对对象属性的访问和更改进行封装。通过这些方法,可以安全地访问或修改对象的内部数据。

Getter与Setter方法的定义与应用

javascript
class Person {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name;
  }

  set name(value) {
    this._name = value;
  }
}

const ming = new Person("小明");
console.log(ming.name); // 小明
ming.name = "小芳";
console.log(ming.name); // 小芳

静态成员

静态成员属于类本身,不属于任何实例。当需要为类创建共享属性或方法时,应使用静态成员。

在类级别定义静态变量与方法

javascript
class Math {
  static PI = 3.141592;

  static circleArea(radius) {
    return this.PI * radius * radius;
  }
}

console.log(Math.PI);       // 3.141592
console.log(Math.circleArea(5)); // 约 78.5398

静态方法与实例方法的区别及其应用

静态方法在类级别上调用,对于执行与实例无关的操作非常实用。而实例方法基于对象的状态,用于访问或修改对象的数据。


在JavaScript中,类的多种特性对于实施面向对象编程模式大有助益。恰当地应用这些特性可以提高代码的可重用性、扩展性和维护性。期望大家能够充分利用JavaScript类的这些强大功能,进行高效的编程。


© Copyright 2023 CLONE CODING