ES6 Class 渐进式详解

ES6 Class 渐进式详解

ES6 引入的 class 是 JavaScript 面向对象编程的语法糖,它让原型继承的写法更清晰、更接近传统面向对象语言(如 Java、C++)的风格。本文将从基础到进阶,配合例子帮你彻底理解。

1. 为什么需要 ES6 Class?

在 ES6 之前,我们是用构造函数 + 原型链实现面向对象的,写法比较繁琐:

javascript

运行

js 复制代码
// ES5 构造函数写法
function Person(name) {
  this.name = name; // 实例属性
}

// 原型方法(共享给所有实例)
Person.prototype.sayHi = function() {
  console.log(`你好,我是${this.name}`);
};

// 实例化
const alice = new Person('Alice');
alice.sayHi(); // 输出:你好,我是Alice

ES6 的 class 把这些逻辑封装得更简洁,本质上还是基于原型链,但可读性大幅提升。

2. 基本语法:定义一个类

class 关键字定义类,类名通常首字母大写:

javascript

运行

js 复制代码
// 定义 Person 类
class Person {
  // 类的主体
}

// 实例化(和构造函数一样,用 new)
const alice = new Person();

这是最简单的类,但还没有属性和方法,接下来我们逐步添加。

3. 构造函数:constructor

constructor 是类的默认方法 ,当你 new 一个实例时,会自动调用它,用来初始化实例属性

javascript

运行

js 复制代码
class Person {
  // 构造函数,接收参数
  constructor(name, age) {
    // this 指向当前实例
    this.name = name; // 实例属性:姓名
    this.age = age;   // 实例属性:年龄
  }
}

// 实例化时传参
const alice = new Person('Alice', 25);
console.log(alice.name); // 输出:Alice
console.log(alice.age);  // 输出:25
  • 如果不写 constructor,类会自动生成一个空的 constructor()
  • this 关键字在类中指向当前实例对象

4. 实例方法:类的行为

在类中定义方法,不需要 function 关键字,直接写方法名即可。这些方法会被添加到类的原型上,所有实例共享:

javascript

运行

js 复制代码
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  // 实例方法:打招呼
  sayHi() {
    console.log(`你好,我是${this.name},今年${this.age}岁`);
  }

  // 实例方法:过生日
  birthday() {
    this.age++; // 修改实例属性
    console.log(`${this.name}过生日了,现在${this.age}岁`);
  }
}

const alice = new Person('Alice', 25);
alice.sayHi();    // 输出:你好,我是Alice,今年25岁
alice.birthday(); // 输出:Alice过生日了,现在26岁

5. 静态成员:类本身的属性 / 方法

static 关键字定义静态属性静态方法 ,它们属于类本身 ,而不是实例,需要通过类名调用:

javascript

运行

js 复制代码
class Person {
  // 静态属性(ES2022 支持,旧版本需用 Person.type = '人类' 定义)
  static type = '人类';

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

  // 静态方法:判断是否是 Person 的实例
  static isPerson(obj) {
    return obj instanceof Person;
  }
}

// 调用静态成员(通过类名)
console.log(Person.type);        // 输出:人类
const alice = new Person('Alice');
console.log(Person.isPerson(alice)); // 输出:true

// 错误:实例无法调用静态成员
// alice.type;   // undefined
// alice.isPerson(); // 报错
  • 静态方法中的 this 指向类本身,而不是实例。

6. 继承:extendssuper

extends 关键字让一个类继承另一个类,子类会拥有父类的所有属性和方法,还可以扩展自己的内容:

javascript

运行

js 复制代码
// 父类(基类)
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHi() {
    console.log(`你好,我是${this.name}`);
  }
}

// 子类(派生类):Student 继承 Person
class Student extends Person {
  constructor(name, studentId) {
    // 必须先调用 super(),它会执行父类的 constructor
    super(name); 
    this.studentId = studentId; // 子类自己的属性
  }

  // 子类自己的方法
  study() {
    console.log(`${this.name}(学号:${this.studentId})正在学习`);
  }

  // 重写父类方法(覆盖)
  sayHi() {
    // 可以通过 super 调用父类的方法
    super.sayHi(); 
    console.log(`我是一名学生,学号是${this.studentId}`);
  }
}

// 实例化子类
const bob = new Student('Bob', '2024001');
bob.sayHi();   // 输出:你好,我是Bob → 我是一名学生,学号是2024001
bob.study();   // 输出:Bob(学号:2024001)正在学习

关键点:

  1. 子类的 constructor 必须先调用 super(),否则会报错(因为子类的 this 是基于父类构建的)。
  2. 子类可以重写 父类的方法(如 sayHi),也可以通过 super.方法名() 调用父类的原方法。

7. Getter 和 Setter:控制属性访问

getset 关键字定义属性访问器,可以在读取或设置属性时添加逻辑(如验证、计算):

javascript

运行

js 复制代码
class Person {
  constructor(name) {
    this._name = name; // 用下划线表示"私有属性"(约定俗成,不是真私有)
  }

  // getter:读取 name 属性时触发
  get name() {
    return this._name.toUpperCase(); // 自动转大写
  }

  // setter:设置 name 属性时触发
  set name(value) {
    if (value.length < 2) {
      console.log('名字太短了!');
      return;
    }
    this._name = value;
  }
}

const alice = new Person('Alice');
console.log(alice.name); // 输出:ALICE(触发 getter)

alice.name = 'Bob';      // 触发 setter
console.log(alice.name); // 输出:BOB

alice.name = 'A';        // 输出:名字太短了!(setter 验证失败)
  • 注意:getset 是方法,但调用时不需要加括号,像普通属性一样访问即可。
  • 这里的 _name 是 "伪私有",外部依然可以直接访问 alice._name(ES2022 支持真私有属性 #name,但兼容性需注意)。

8. 类的本质:语法糖

虽然 class 看起来像新东西,但本质上还是函数 + 原型链,我们可以验证一下:

javascript

运行

js 复制代码
class Person {}

// 1. 类的类型是 function
console.log(typeof Person); // 输出:function

// 2. 类有 prototype 属性(和构造函数一样)
console.log(Person.prototype); // 输出:{ constructor: Person }

// 3. 实例的 __proto__ 指向类的 prototype
const alice = new Person();
console.log(alice.__proto__ === Person.prototype); // 输出:true

所以 class 只是让原型继承的写法更优雅,底层逻辑和 ES5 是一致的。

总结

  • class 是 ES6 的语法糖,简化了面向对象编程。
  • constructor 用于初始化实例属性,new 时自动调用。
  • 实例方法定义在原型上,静态方法用 static 定义,属于类本身。
  • 继承用 extends,子类 constructor 必须先调用 super()
  • get/set 用于控制属性的读写逻辑。
相关推荐
小番茄夫斯基2 小时前
前端开发的过程中,需要mock 数据,但是走的原来的接口,要怎么做
前端·javascript
Devin_chen2 小时前
原型链大白话详解
javascript
peachSoda72 小时前
前端想转AI全栈-初步练习记录
前端·人工智能
树上有只程序猿2 小时前
低代码平台选型指南,10 款热门工具对比
前端·后端
@PHARAOH2 小时前
WHAT - 硬链接 hard link 和软链接 symlink
前端
cyforkk2 小时前
前端限流实战:从 429 状态码处理到消除“双重报错”
前端·状态模式
陈林梓2 小时前
Qiankun 微前端配置详解
前端
英俊潇洒美少年2 小时前
Vue3 的 JSX 函数组件,每次更新都会重新运行吗?
前端·javascript·vue.js