类(Class)
概述
ES6 引入了类(class)语法,提供了更清晰、更面向对象的方式来创建对象和处理继承。
基本语法
类定义
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
greet() {
return `Hello, I'm ${this.name}`;
}
// 获取器
get info() {
return `${this.name}, ${this.age} years old`;
}
// 设置器
set nickname(value) {
this._nickname = value;
}
get nickname() {
return this._nickname || this.name;
}
}
const person = new Person('John', 25);
console.log(person.greet()); // "Hello, I'm John"
console.log(person.info); // "John, 25 years old"
person.nickname = 'Johnny';
console.log(person.nickname); // "Johnny"
类表达式
// 匿名类表达式
const Person = class {
constructor(name) {
this.name = name;
}
};
// 命名类表达式
const Person = class MyClass {
constructor(name) {
this.name = name;
}
getClassName() {
return MyClass.name;
}
};
const person = new Person('John');
console.log(person.getClassName()); // "MyClass"
静态成员
静态方法
class MathUtils {
static add(a, b) {
return a + b;
}
static subtract(a, b) {
return a - b;
}
static multiply(a, b) {
return a * b;
}
}
console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.subtract(5, 3)); // 2
console.log(MathUtils.multiply(5, 3)); // 15
静态属性
class Person {
static count = 0;
static species = 'Homo sapiens';
constructor(name) {
this.name = name;
Person.count++;
}
static getCount() {
return Person.count;
}
}
const p1 = new Person('John');
const p2 = new Person('Jane');
console.log(Person.count); // 2
console.log(Person.getCount()); // 2
console.log(Person.species); // "Homo sapiens"
继承
基本继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a noise.`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
return `${this.name} barks.`;
}
fetch() {
return `${this.name} fetches the ball.`;
}
}
const dog = new Dog('Rex', 'German Shepherd');
console.log(dog.speak()); // "Rex barks."
console.log(dog.fetch()); // "Rex fetches the ball."
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
super 关键字
class Vehicle {
constructor(type, speed) {
this.type = type;
this.speed = speed;
}
describe() {
return `This is a ${this.type} moving at ${this.speed} mph.`;
}
}
class Car extends Vehicle {
constructor(speed, brand) {
super('car', speed);
this.brand = brand;
}
describe() {
const baseDescription = super.describe();
return `${baseDescription} It's a ${this.brand}.`;
}
}
const car = new Car(60, 'Toyota');
console.log(car.describe());
// "This is a car moving at 60 mph. It's a Toyota."
继承静态成员
class Shape {
static create(type, ...args) {
switch (type) {
case 'circle':
return new Circle(...args);
case 'rectangle':
return new Rectangle(...args);
}
}
static getShapeCount() {
return this.count || 0;
}
}
class Circle extends Shape {
static count = 0;
constructor(radius) {
super();
this.radius = radius;
Circle.count++;
}
get area() {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
static count = 0;
constructor(width, height) {
super();
this.width = width;
this.height = height;
Rectangle.count++;
}
get area() {
return this.width * this.height;
}
}
const circle = Shape.create('circle', 5);
const rectangle = Shape.create('rectangle', 4, 6);
console.log(circle.area); // 78.53981633974483
console.log(rectangle.area); // 24
console.log(Circle.getShapeCount()); // 1
console.log(Rectangle.getShapeCount()); // 1
私有成员
私有字段
class BankAccount {
#balance = 0; // 私有字段
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return true;
}
return false;
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
return true;
}
return false;
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
account.withdraw(30);
console.log(account.getBalance()); // 120
// console.log(account.#balance); // SyntaxError: Private field
私有方法
class User {
#password;
constructor(username, password) {
this.username = username;
this.#password = password;
}
#hashPassword(password) {
// 简单的哈希示例
return password.split('').reverse().join('');
}
#validatePassword(password) {
return this.#password === this.#hashPassword(password);
}
authenticate(password) {
return this.#validatePassword(password);
}
changePassword(oldPassword, newPassword) {
if (this.#validatePassword(oldPassword)) {
this.#password = this.#hashPassword(newPassword);
return true;
}
return false;
}
}
const user = new User('john', 'secret');
console.log(user.authenticate('secret')); // true
// user.#hashPassword('test'); // SyntaxError: Private method
抽象类模拟
使用 new.target
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error('Shape is an abstract class');
}
}
area() {
throw new Error('area() must be implemented');
}
perimeter() {
throw new Error('perimeter() must be implemented');
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
perimeter() {
return 2 * Math.PI * this.radius;
}
}
// const shape = new Shape(); // Error: Shape is an abstract class
const circle = new Circle(5);
console.log(circle.area()); // 78.53981633974483
Mixin 模式
基本 Mixin
const Serializable = (superclass) => class extends superclass {
serialize() {
return JSON.stringify(this);
}
static deserialize(json) {
return Object.assign(new this(), JSON.parse(json));
}
};
const Validatable = (superclass) => class extends superclass {
validate() {
for (const key of Object.keys(this)) {
if (this[key] === null || this[key] === undefined) {
return false;
}
}
return true;
}
};
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
}
// 组合多个 mixin
class EnhancedUser extends Serializable(Validatable(User)) {
constructor(name, email) {
super(name, email);
}
}
const user = new EnhancedUser('John', 'john@example.com');
console.log(user.validate()); // true
console.log(user.serialize()); // {"name":"John","email":"john@example.com"}
const deserialized = EnhancedUser.deserialize('{"name":"Jane","email":"jane@example.com"}');
console.log(deserialized.name); // "Jane"
实际应用示例
1. 事件发射器
class EventEmitter {
#events = new Map();
on(event, callback) {
if (!this.#events.has(event)) {
this.#events.set(event, new Set());
}
this.#events.get(event).add(callback);
return this;
}
off(event, callback) {
if (this.#events.has(event)) {
this.#events.get(event).delete(callback);
}
return this;
}
emit(event, ...args) {
if (this.#events.has(event)) {
for (const callback of this.#events.get(event)) {
callback.apply(this, args);
}
}
return this;
}
once(event, callback) {
const wrapper = (...args) => {
this.off(event, wrapper);
callback.apply(this, args);
};
return this.on(event, wrapper);
}
}
const emitter = new EventEmitter();
emitter.on('data', (value) => console.log('Received:', value));
emitter.emit('data', 'Hello'); // "Received: Hello"
2. 状态管理
class Store {
#state;
#listeners = new Set();
constructor(initialState = {}) {
this.#state = { ...initialState };
}
get state() {
return { ...this.#state };
}
setState(updater) {
const newState = typeof updater === 'function'
? updater(this.#state)
: updater;
this.#state = { ...this.#state, ...newState };
this.#notify();
}
subscribe(listener) {
this.#listeners.add(listener);
return () => this.#listeners.delete(listener);
}
#notify() {
for (const listener of this.#listeners) {
listener(this.state);
}
}
}
const store = new Store({ count: 0 });
const unsubscribe = store.subscribe((state) => {
console.log('State changed:', state);
});
store.setState({ count: 1 }); // "State changed: { count: 1 }"
store.setState((state) => ({ count: state.count + 1 })); // "State changed: { count: 2 }"
3. 数据验证
class Validator {
#rules = new Map();
addRule(field, validator, message) {
if (!this.#rules.has(field)) {
this.#rules.set(field, []);
}
this.#rules.get(field).push({ validator, message });
return this;
}
validate(data) {
const errors = [];
for (const [field, rules] of this.#rules) {
for (const { validator, message } of rules) {
if (!validator(data[field])) {
errors.push({ field, message });
}
}
}
return {
valid: errors.length === 0,
errors
};
}
}
const userValidator = new Validator()
.addRule('name', (v) => v && v.length >= 2, 'Name must be at least 2 characters')
.addRule('email', (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v), 'Invalid email')
.addRule('age', (v) => v >= 18 && v <= 120, 'Age must be between 18 and 120');
const result = userValidator.validate({
name: 'John',
email: 'john@example.com',
age: 25
});
console.log(result.valid); // true
最佳实践
- 使用类而非构造函数:更清晰的语法
- 私有字段保护数据:使用
#语法 - 静态方法用于工具函数:不需要实例化
- 继承时调用 super():正确初始化父类
- 使用 getter/setter:控制属性访问
// 好的做法
class User {
#email;
constructor(name, email) {
this.name = name;
this.#email = email;
}
get email() {
return this.#email;
}
set email(value) {
if (!this.#isValidEmail(value)) {
throw new Error('Invalid email');
}
this.#email = value;
}
#isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
static createFromJSON(json) {
const data = JSON.parse(json);
return new User(data.name, data.email);
}
}
参考
目录