人人都会AI编程

类的定义、构造函数、实例方法、静态方法

更新时间:2026-07-11

ES6 引入的 class 关键字极大改善了 JavaScript 面向对象编程的语法体验。它不是一门新的面向对象机制,本质上依然是基于原型的继承,只是提供了一套更清晰、更贴近传统类式语言的写法。对于从 Java 或 C++ 转过来的开发者而言,class 语法降低了学习成本;对于原本熟悉原型链的开发者而言,class 则让代码结构更紧凑,意图表达更明确。

类的定义

定义一个类使用 class 关键字,类名通常采用大驼峰命名法(PascalCase)。类的主体是一对花括号,内部可以定义构造函数、实例方法和静态方法。

class Person {
  // 类的主体
}

类与函数不同,它不存在变量提升。这意味着必须先在代码中定义类,然后才能使用它,否则会抛出 ReferenceError。这一点与实际工作场景相关:如果你在一个文件中使用 new MyClass(),务必保证该类已经完成了定义或导入。

类表达式也是合法的,你可以像定义匿名函数那样创建一个匿名类,并将其赋值给一个变量:

const Animal = class {
  // ...
};

不过日常开发中,命名类声明更常见,因为它便于调试和代码浏览(类名会在堆栈跟踪中显示)。

构造函数(constructor)

constructor 是一个特殊的方法,用于创建和初始化类的实例。通过 new 关键字调用类时,构造函数会被自动执行。每个类只能有一个 constructor,如果不显式定义,引擎会提供一个默认为空的构造函数。

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    // 构造函数内可以执行任意初始化逻辑,但不能返回非 undefined 的对象
  }
}

const alice = new Person('Alice', 28);
console.log(alice.name); // 'Alice'

构造函数内部的 this 指向新创建的实例对象。你可以在这里设置实例属性、调用其他方法或执行任何一次性初始逻辑。常见的做法是接收外部参数,并将其绑定到实例上。

如果你希望禁止直接调用构造函数(例如实现一个工厂模式),可以在构造函数中加入检测逻辑:

class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }
}

实例方法

实例方法是定义在类的原型对象上的函数,所有实例对象可以共享同一个方法引用,而不是每个实例都拥有一份拷贝。定义实例方法只需在类主体内直接写函数即可,无需使用 function 关键字。

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

  // 实例方法
  greet() {
    return `你好,我叫${this.name}`;
  }

  // 实例方法中可以访问 this,调用其他实例方法或访问属性
  introduce() {
    console.log(this.greet());
  }
}

const bob = new Person('Bob');
bob.introduce(); // 输出:你好,我叫Bob

关键细节:

  • 实例方法内部的 this 在调用时动态确定,通常指向调用该方法的对象。但如果你把方法单独提取出来执行,this 可能会丢失或指向全局对象(严格模式下为 undefined)。这是类方法最常见的坑点之一:
  const fn = bob.introduce;
  fn(); // 报错或输出 undefined,因为 this 不再是 bob
  

解决办法是使用箭头函数来定义属性,或者在构造函数内用 bind 绑定 this,但前者会占用实例属性,后者略繁琐。现代开发中,经常配合框架(如 React)使用自动绑定,或在需要时手动绑定。

  • 实例方法可以使用 getset 关键字定义访问器属性,这样可以像访问普通属性一样调用方法,内部却能进行额外的逻辑处理。访问器使用在第 11 章前面已有介绍,这里只做示例:
  class Person {
    constructor(first, last) {
      this.first = first;
      this.last = last;
    }

    get fullName() {
      return `${this.first} ${this.last}`;
    }

    set fullName(value) {
      [this.first, this.last] = value.split(' ');
    }
  }
  

静态方法

静态方法是属于类本身的方法,而不是属于某个实例。它们通常用来定义工具函数、工厂方法或者与具体实例无关的操作。定义方式是在方法前加上 static 关键字。

class MathUtils {
  static add(a, b) {
    return a + b;
  }

  static createRandomArray(length) {
    return Array.from({ length }, () => Math.floor(Math.random() * 100));
  }
}

// 直接通过类名调用,无需创建实例
console.log(MathUtils.add(3, 5)); // 8
const nums = MathUtils.createRandomArray(5);

静态方法的特点与用途:

  • 静态方法内无法通过 this 访问实例属性或实例方法,因为 this 指向的是类本身(即构造函数对象),而不是某个实例。
  • 它们常用于封装与类强关联但无需实例数据的逻辑。例如 Date.now()Array.isArray() 都是静态方法的典型应用。
  • 如果一个静态方法需要根据当前类动态创建实例(例如实现“工厂”方法),可以使用 new this(),这样在子类中也能正确返回子类的实例。
  class Vehicle {
    constructor(type) {
      this.type = type;
    }

    static create(type) {
      return new this(type); // 这里的 this 指向调用时所在的类
    }
  }

  class Car extends Vehicle {
    constructor() {
      super('car');
    }
  }

  const vehicle = Vehicle.create('truck');
  const car = Car.create();
  console.log(car instanceof Car); // true
  

总结

类是 JavaScript 对象创建与继承的现代语法糖,它没有改变底层的原型机制,却给开发者提供了更熟悉的代码组织方式。实际运用中,把握以下几点可以让你少走弯路:

  • 构造函数负责初始化实例状态。
  • 实例方法挂载在原型上,所有实例共享,调用时注意 this 的绑定。
  • 静态方法挂载在类自身上,适合放置工具类和工厂方法。
  • 始终记住类没有提升,先定义后使用。