Skip to content

类是用于创建对象的模板。它们用代码封装数据以对其进行处理。JS 中的类建立在原型之上,同时还具有一些类独有的语法和语义。

类实际上是“特殊的函数

构造函数

ES6之前

对比以下通过面向对象的构造函数实现的封装:

js
function Person(name,age) {
  this.name = name
  this.age = age

  // 对象方法
  this.sing = () => {
    console.log('我会唱歌')
  }
}

// 实例对像,获得了构造函数中封装的所有逻辑
let p1 = new Person('刘德华', 50)
console.log(p1.name)   // 刘德华

// 实例对象
let p2 = new Person('张学友', 55)
console.log(p2.name)   // 

// 不同对象的方法内存不一样,浪费内存
console.log(p1.sing === p2.sing)  // false

封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。

同样的将变量和函数组合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间是彼此不影响的。

总结:

  1. 构造函数体现了面向对象的封装特性
  2. 构造函数实例创建的对象彼此独立、互不影响

封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。

前面我们学过的构造函数方法很好用,但是 存在浪费内存的问题

js
// 定义构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;

  // 实例方法
  this.sayHello = function() {
    console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
  };
}

// 添加原型方法,不会浪费内存
Person.prototype.getDetails = function() {
  return `${this.name} is ${this.age} years old.`;
};

// 创建实例
var john = new Person('John Doe', 30);

// 调用实例方法
john.sayHello();
console.log(john.getDetails());

Class语法糖

在JavaScript中,class 是 ECMAScript 6(ES6)引入的一种新的语法结构,它使得开发者能够以一种更加清晰、简洁的方式定义类(classes),从而更好地支持面向对象编程(OOP)特性。尽管JavaScript本质上是一种基于原型的语言,但 class 语法让开发者可以像在其他支持类的编程语言中那样创建类,并通过继承实现复用和扩展。

constructor 方法是用于创建和初始化一个由类创建的对象的特殊方法。

js
// 定义类
class Person {
  // 构造函数
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  // 原型方法(默认就是定义在原型上)
  getDetails() {
    return `${this.name} is ${this.age} years old.`;
  }
}

// 创建实例
const jane = new Person('Jane Smith', 28);

// 调用实例方法
console.log(jane.getDetails());

class 还支持继承:

js
// 定义一个Employee类,继承自Person类
class Employee extends Person {
  constructor(name, age, position) {
    super(name, age); // 使用super调用父类的构造函数
    this.position = position;
  }

  introduce() {
    console.log(`I am ${this.name}, a ${this.position}.`);
  }
}

let bob = new Employee('Bob', 30, 'Engineer');
bob.sayHello(); // 继承自Person类的方法
bob.introduce(); // Employee类特有的方法

静态属性和方法

static 关键字用来定义类的静态方法或字段。静态属性(字段和方法)被定义在类的自身而不是类的实例上。

js
class Person {
    static age = 18
    static getName() {
        console.log('hello world');
    }
}

const p = new Person();
Person.getName()                // 通过类调用静态方法
console.log(Person.age);        // 通过类调用静态属性

私有属性

从类的外部引用私有字段是错误的,它们只能在类主体的内部被读写。私有字段只能在字段声明中预先声明。它们不像普通属性那样可以通过赋值创建。

js
class Rectangle {
  // 私有字段必须在封闭类中声明。
  #height = 0;
  #width;
  constructor(height, width) {
    this.#height = height;
    this.#width = width;
  }
  getHeight() {
    return this.#height;
  }
}

const r = new Rectangle(10, 20);
console.log(r.height);       // undefined
console.log(r.getHeight());  // 10

继承

extends 关键字用于类声明类表达式中,用以创建一个类作为另一构造函数(类或函数)的子类。

如果子类中定义了构造函数,那么它必须先调用 super() 才能使用 thissuper 关键字也可以用来调用父类中对应的方法。

js
class Animal {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    console.log(this.name);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 使用super关键字调用父类构造函数
    this.breed = breed;
  }
  bark() {
    console.log('Woof!');
  }
}

let dog = new Dog('Charlie', 'Poodle');
dog.sayName(); // 输出: Charlie
dog.bark(); // 输出: Woof!