一、Class 的本质
ES6 的 class 本质上是构造函数的语法糖,其功能大部分可通过 ES5 实现。新语法旨在使对象原型的写法更清晰,更符合面向对象编程习惯。
二、核心特性详解
1. 原型方法与属性定义
- 类中所有方法(除非显式定义在
this上)均定义在类的prototype对象上。 - 类的
prototype.constructor属性指向类本身(与构造函数一致)。 - 重要区别:类中定义的方法不可枚举(ES5 构造函数的方法可枚举)。
2. 构造函数
constructor()是类的默认方法,new实例化时自动调用。- 若未显式定义,JS 引擎会自动添加一个空的
constructor()。
3. 实例化要求
- 必须使用
new调用,直接调用类(如MyClass())会抛出错误。
4. 实例属性定义方式
-
传统方式:在
constructor()内通过this定义。class Person { constructor() { this.name = 'John'; // 实例属性 } } -
ES2022 新方式:直接在类顶层声明(推荐)。
class Person { name = 'John'; // 顶层实例属性 }
5. 访问器属性
- 使用
get/set拦截属性存取:class Square { get html() { return this.element.innerHTML; } set html(value) { this.element.innerHTML = value; } }
6. 动态属性名
- 属性名可使用表达式:
let methodName = 'getArea'; class Square { [methodName]() { /* ... */ } // 动态方法名 }
7. 类表达式
-
类可通过表达式定义,类名(内部名)仅在内部可见:
const MyClass = class Me { getClassName() { return Me.name; // 'Me' 仅在类内部可用 } }; let inst = new MyClass(); inst.getClassName(); // "Me" console.log(Me.name); // 错误:Me 未定义
8. 静态成员
-
用
static关键字定义:- 静态方法/属性属于类本身,实例不可继承。
- 父类静态方法可被子类继承。
class MyClass { static staticMethod() { return 'Hello'; } static staticProp = 42; } MyClass.staticMethod(); // "Hello"
9. 私有属性(ES2022)
-
属性名前加
#表示私有:- 仅在类内部可访问。
- 访问不存在的私有属性会报错。
- 允许在实例方法中通过
this.#prop访问。
class Counter { #count = 0; // 私有属性 increment() { this.#count++; } }
10. 类继承 (extends 与 super)
-
通过
extends实现继承。 -
子类必须在
constructor中调用super()才能使用this。 -
与 ES5 继承的关键区别:
- ES5 继承:先创建子类实例 (
this),再通过Parent.call(this)继承父类属性。 - ES6 继承:先调用
super()创建父类实例(建立this),再初始化子类。
class Parent {} class Child extends Parent { constructor() { super(); // 必须先调用 super() this.childProp = 1; } }需要注意的是ES6 的
class继承在语法上表现为先继承(通过super())再初始化实例,但是在底层实现上还是先创建实例再设置原型链继承。class A { constructor() { console.log('A constructor start - this:', this); this.a = 'a'; console.log('A constructor end'); } } class B extends A { constructor() { console.log('B constructor start - this:', this); // ❌ 这里不能访问 this // 1. 调用 super() 相当于: // - 创建实例对象 // - 设置 B.prototype -> A.prototype 的原型链 // - 执行 A 构造函数 super(); console.log('B constructor after super - this:', this); // ✅ 可以访问 this // 2. 初始化子类属性 this.b = 'b'; console.log('B constructor end'); } } // 验证原型链 console.log('B.prototype.__proto__ === A.prototype:', B.prototype.__proto__ === A.prototype); // true // 创建实例 const obj = new B(); /* 输出顺序: B constructor start - this: undefined A constructor start - this: B {} A constructor end B constructor after super - this: B { a: 'a' } B constructor end */ - ES5 继承:先创建子类实例 (
### 三、总结
| 特性 | 关键点 |
| --------- | ----------------------------------------------- |
| **原型方法** | 定义于 `prototype`,方法不可枚举 |
| **构造函数** | 必需,未定义时自动添加空函数 |
| **实例化** | 必须使用 `new` |
| **实例属性** | 支持传统 (`constructor` + `this`) 和 ES2022 顶层定义方式 |
| **访问器** | `get`/`set` 实现属性存取拦截 |
| **动态属性名** | 使用 `[expression]` 语法 |
| **类表达式** | 类名仅在内部可见 |
| **静态成员** | `static` 定义,类直接访问,可继承 |
| **私有属性** | `#` 前缀,仅类内部访问 |
| **继承机制** | `extends` + `super()`,先创建父类实例再初始化子类(与 ES5 时序相反) |
> **核心价值**:`class` 语法提供了更清晰、更安全的面向对象编程模式,通过规范化语法减少原型链操作错误,并引入私有属性等现代化特性,显著提升代码可维护性。