个人主页:Guiat
归属专栏:HTML CSS JavaScript
文章目录
- 1. JavaScript 中的面向对象编程
- 1.1 对象基础
- 1.2 构造函数
- 1.3 原型和原型链
- 1.4 ES6 类
- 1.5 继承
- 1.6 封装
- 2. 创建型设计模式
- 2.1 工厂模式
- 2.2 单例模式
- 2.3 建造者模式
- 2.4 原型模式
- 3. 结构型设计模式
- 3.1 适配器模式
- 3.2 装饰器模式
- 3.3 代理模式
- 3.4 组合模式
- 4. 行为型设计模式
- 4.1 观察者模式
- 4.2 策略模式
- 4.3 命令模式
- 4.4 迭代器模式
- 4.5 中介者模式
- 5. 实际应用案例
- 5.1 表单验证系统
正文
1. JavaScript 中的面向对象编程
1.1 对象基础
在 JavaScript 中,对象是键值对的集合,几乎所有事物都是对象。
// 对象字面量
const person = {name: 'John',age: 30,greet: function() {return `Hello, my name is ${this.name}`;}
};// 访问属性
console.log(person.name); // "John"
console.log(person['age']); // 30// 调用方法
console.log(person.greet()); // "Hello, my name is John"
1.2 构造函数
构造函数用于创建和初始化对象。
function Person(name, age) {this.name = name;this.age = age;this.greet = function() {return `Hello, my name is ${this.name}`;};
}// 使用 new 关键字创建实例
const john = new Person('John', 30);
const jane = new Person('Jane', 25);console.log(john.greet()); // "Hello, my name is John"
console.log(jane.greet()); // "Hello, my name is Jane"// 验证实例类型
console.log(john instanceof Person); // true
1.3 原型和原型链
每个 JavaScript 对象都连接到一个原型对象,可以从中继承属性和方法。
function Person(name, age) {this.name = name;this.age = age;
}// 在原型上添加方法
Person.prototype.greet = function() {return `Hello, my name is ${this.name}`;
};const john = new Person('John', 30);
const jane = new Person('Jane', 25);console.log(john.greet()); // "Hello, my name is John"
console.log(john.greet === jane.greet); // true - 方法共享// 原型链
console.log(john.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
1.4 ES6 类
ES6 引入了类语法,使面向对象编程更直观。
class Person {constructor(name, age) {this.name = name;this.age = age;}// 实例方法greet() {return `Hello, my name is ${this.name}`;}// 静态方法static createAnonymous() {return new Person('Anonymous', 0);}// getterget profile() {return `${this.name}, ${this.age} years old`;}// setterset profile(value) {[this.name, this.age] = value.split(',');this.age = parseInt(this.age, 10);}
}const john = new Person('John', 30);
console.log(john.greet()); // "Hello, my name is John"// 静态方法调用
const anonymous = Person.createAnonymous();
console.log(anonymous.name); // "Anonymous"
1.5 继承
继承允许一个类基于另一个类创建,共享和扩展其功能。
// ES5 继承
function Person(name, age) {this.name = name;this.age = age;
}Person.prototype.greet = function() {return `Hello, my name is ${this.name}`;
};function Employee(name, age, company) {// 调用父类构造函数Person.call(this, name, age);this.company = company;
}// 设置原型链
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;// 添加新方法
Employee.prototype.work = function() {return `${this.name} works at ${this.company}`;
};// ES6 继承
class Person {constructor(name, age) {this.name = name;this.age = age;}greet() {return `Hello, my name is ${this.name}`;}
}class Employee extends Person {constructor(name, age, company) {super(name, age); // 调用父类构造函数this.company = company;}work() {return `${this.name} works at ${this.company}`;}// 覆盖父类方法greet() {return `${super.greet()} and I work at ${this.company}`;}
}const jane = new Employee('Jane', 25, 'Facebook');
console.log(jane.greet()); // "Hello, my name is Jane and I work at Facebook"
1.6 封装
封装是隐藏对象内部状态和实现细节的技术。
// 使用闭包实现私有变量
function Person(name, age) {// 私有变量let _name = name;let _age = age;// 公共接口this.getName = function() {return _name;};this.setName = function(name) {if (name.length > 0) {_name = name;}};
}// ES2022 私有字段和方法
class Person {// 私有字段#name;#age;constructor(name, age) {this.#name = name;this.#age = age;}// 公共方法getName() {return this.#name;}// 私有方法#validateAge(age) {return age > 0 && age < 120;}
}
2. 创建型设计模式
创建型设计模式关注对象的创建机制,以适合特定情况的方式创建对象。
2.1 工厂模式
工厂模式通过一个中央函数创建对象。
// 简单工厂
function createUser(type) {if (type === 'admin') {return {name: 'Admin User',permissions: ['read', 'write', 'delete']};} else if (type === 'user') {return {name: 'Regular User',permissions: ['read']};}
}const adminUser = createUser('admin');
console.log(adminUser.permissions); // ["read", "write", "delete"]// 工厂方法
class UserFactory {static createAdmin(name) {return {name,permissions: ['read', 'write', 'delete'],role: 'admin'};}static createRegular(name) {return {name,permissions: ['read'],role: 'user'};}
}const admin = UserFactory.createAdmin('John');
const user = UserFactory.createRegular('Jane');
2.2 单例模式
单例模式确保一个类只有一个实例,并提供一个全局访问点。
// 简单单例
const Singleton = (function() {let instance;function createInstance() {return {name: 'Singleton Instance',getData: function() {return this.name;}};}return {getInstance: function() {if (!instance) {instance = createInstance();}return instance;}};
})();const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true// ES6 单例
class Database {constructor(host, port) {if (Database.instance) {return Database.instance;}this.host = host;this.port = port;this.connected = false;Database.instance = this;}connect() {if (this.connected) {return this;}console.log(`Connecting to ${this.host}:${this.port}`);this.connected = true;return this;}
}const db1 = new Database('localhost', 3306).connect();
const db2 = new Database('example.com', 8080).connect();
console.log(db1 === db2); // true
console.log(db2.host); // "localhost" (不是 "example.com")
2.3 建造者模式
建造者模式将复杂对象的构建与其表示分离,使同一构建过程可创建不同表示。
// 建造者模式
class HouseBuilder {constructor() {this.house = {};}setBuildingType(buildingType) {this.house.buildingType = buildingType;return this;}setWallMaterial(wallMaterial) {this.house.wallMaterial = wallMaterial;return this;}setNumberOfDoors(number) {this.house.doors = number;return this;}setNumberOfWindows(number) {this.house.windows = number;return this;}build() {return this.house;}
}const house = new HouseBuilder().setBuildingType('apartment').setWallMaterial('brick').setNumberOfDoors(2).setNumberOfWindows(4).build();// 使用指挥者
class HouseDirector {buildCottage(builder) {return builder.setBuildingType('cottage').setWallMaterial('wood').setNumberOfDoors(2).setNumberOfWindows(8).build();}buildApartment(builder) {return builder.setBuildingType('apartment').setWallMaterial('concrete').setNumberOfDoors(1).setNumberOfWindows(4).build();}
}const director = new HouseDirector();
const cottage = director.buildCottage(new HouseBuilder());
2.4 原型模式
原型模式基于现有对象创建新对象,而不是从头构建。
// ES5 方式
const carPrototype = {init: function(make, model, year) {this.make = make;this.model = model;this.year = year;return this;},getInfo: function() {return `${this.make} ${this.model} (${this.year})`;}
};const car1 = Object.create(carPrototype).init('Toyota', 'Camry', 2020);
const car2 = Object.create(carPrototype).init('Honda', 'Accord', 2022);// 使用类
class Car {constructor(make, model, year) {this.make = make;this.model = model;this.year = year;}getInfo() {return `${this.make} ${this.model} (${this.year})`;}clone() {return new Car(this.make, this.model, this.year);}
}const tesla = new Car('Tesla', 'Model S', 2020);
const clonedTesla = tesla.clone();
clonedTesla.year = 2021;
3. 结构型设计模式
结构型设计模式关注类和对象的组合,形成更大的结构。
3.1 适配器模式
适配器模式使接口不兼容的类能一起工作。
// 旧接口
class OldCalculator {constructor() {this.operations = function(term1, term2, operation) {switch(operation) {case 'add':return term1 + term2;case 'sub':return term1 - term2;default:return NaN;}};}
}// 新接口
class NewCalculator {constructor() {this.add = function(term1, term2) {return term1 + term2;};this.sub = function(term1, term2) {return term1 - term2;};}
}// 适配器
class CalculatorAdapter {constructor() {const newCalc = new NewCalculator();this.operations = function(term1, term2, operation) {switch(operation) {case 'add':return newCalc.add(term1, term2);case 'sub':return newCalc.sub(term1, term2);default:return NaN;}};}
}// 客户端代码使用旧接口
const oldCalc = new OldCalculator();
console.log(oldCalc.operations(10, 5, 'add')); // 15// 适配新接口
const adaptedCalc = new CalculatorAdapter();
console.log(adaptedCalc.operations(10, 5, 'add')); // 15
3.2 装饰器模式
装饰器模式动态地向对象添加新功能,而不改变其原有结构。
// 基础组件
class Coffee {cost() {return 5;}description() {return 'Plain coffee';}
}// 装饰器
class MilkDecorator {constructor(coffee) {this.coffee = coffee;}cost() {return this.coffee.cost() + 1;}description() {return `${this.coffee.description()} with milk`;}
}class SugarDecorator {constructor(coffee) {this.coffee = coffee;}cost() {return this.coffee.cost() + 0.5;}description() {return `${this.coffee.description()} with sugar`;}
}// 使用
let coffee = new Coffee();
console.log(coffee.description()); // "Plain coffee"
console.log(coffee.cost()); // 5coffee = new MilkDecorator(coffee);
console.log(coffee.description()); // "Plain coffee with milk"
console.log(coffee.cost()); // 6coffee = new SugarDecorator(coffee);
console.log(coffee.description()); // "Plain coffee with milk with sugar"
console.log(coffee.cost()); // 6.5// JavaScript 装饰器(提案)
function readonly(target, name, descriptor) {descriptor.writable = false;return descriptor;
}class User {@readonlyusername() {return 'default';}
}
3.3 代理模式
代理模式为另一个对象提供替代或占位符,以控制对原始对象的访问。
// 真实主题
class RealImage {constructor(filename) {this.filename = filename;this.loadFromDisk();}loadFromDisk() {console.log(`Loading ${this.filename} from disk`);}display() {console.log(`Displaying ${this.filename}`);}
}// 代理
class ProxyImage {constructor(filename) {this.filename = filename;this.realImage = null;}display() {if (!this.realImage) {this.realImage = new RealImage(this.filename);}this.realImage.display();}
}// 客户端
const image = new ProxyImage('high-res-photo.jpg');
// 没有加载图像
console.log('Image object created');// 加载并显示图像
image.display();// 再次显示(不会重新加载)
image.display();
3.4 组合模式
组合模式将对象组合成树状结构,表示"部分-整体"层次结构。
// 组件接口
class UIComponent {constructor(name) {this.name = name;}render() {throw new Error('Render method must be implemented');}getComponentSize() {throw new Error('getComponentSize method must be implemented');}
}// 叶子组件
class Button extends UIComponent {constructor(name) {super(name);}render() {console.log(`Rendering Button: ${this.name}`);}getComponentSize() {return 1;}
}class Input extends UIComponent {constructor(name) {super(name);}render() {console.log(`Rendering Input: ${this.name}`);}getComponentSize() {return 1;}
}// 容器组件
class Form extends UIComponent {constructor(name) {super(name);this.components = [];}add(component) {this.components.push(component);}remove(component) {const index = this.components.indexOf(component);if (index !== -1) {this.components.splice(index, 1);}}render() {console.log(`Rendering Form: ${this.name}`);this.components.forEach(component => component.render());}getComponentSize() {return this.components.reduce((size, component) => {return size + component.getComponentSize();}, 0);}
}// 客户端代码
const loginForm = new Form('Login Form');
loginForm.add(new Input('Username'));
loginForm.add(new Input('Password'));
loginForm.add(new Button('Submit'));const registrationForm = new Form('Registration Form');
registrationForm.add(new Input('Name'));
registrationForm.add(new Input('Email'));
registrationForm.add(new Button('Register'));const mainForm = new Form('Main Form');
mainForm.add(loginForm);
mainForm.add(registrationForm);// 渲染整个 UI 树
mainForm.render();
console.log(`Total components: ${mainForm.getComponentSize()}`);
4. 行为型设计模式
行为型设计模式关注对象之间的通信和职责分配。
4.1 观察者模式
观察者模式定义对象间的一对多依赖关系,使一个对象改变时,所有依赖它的对象都得到通知。
// 主题
class Subject {constructor() {this.observers = [];}subscribe(observer) {this.observers.push(observer);}unsubscribe(observer) {this.observers = this.observers.filter(obs => obs !== observer);}notify(data) {this.observers.forEach(observer => observer.update(data));}
}// 观察者
class Observer {constructor(name) {this.name = name;}update(data) {console.log(`${this.name} received: ${data}`);}
}// 使用
const subject = new Subject();const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');subject.subscribe(observer1);
subject.subscribe(observer2);subject.notify('Hello World!');
// "Observer 1 received: Hello World!"
// "Observer 2 received: Hello World!"subject.unsubscribe(observer1);
subject.notify('Hello Again!');
// "Observer 2 received: Hello Again!"
4.2 策略模式
策略模式定义了一系列算法,将每个算法封装起来,使它们可以互换使用。
// 策略接口
class PaymentStrategy {pay(amount) {throw new Error('pay method must be implemented');}
}// 具体策略
class CreditCardStrategy extends PaymentStrategy {constructor(cardNumber, name, cvv, expiryDate) {super();this.cardNumber = cardNumber;this.name = name;this.cvv = cvv;this.expiryDate = expiryDate;}pay(amount) {console.log(`Paying ${amount} using Credit Card`);// 处理信用卡支付逻辑}
}class PayPalStrategy extends PaymentStrategy {constructor(email, password) {super();this.email = email;this.password = password;}pay(amount) {console.log(`Paying ${amount} using PayPal`);// 处理 PayPal 支付逻辑}
}// 上下文
class ShoppingCart {constructor() {this.items = [];}addItem(item) {this.items.push(item);}calculateTotal() {return this.items.reduce((total, item) => total + item.price, 0);}checkout(paymentStrategy) {const amount = this.calculateTotal();paymentStrategy.pay(amount);}
}// 客户端代码
const cart = new ShoppingCart();
cart.addItem({ name: 'Item 1', price: 100 });
cart.addItem({ name: 'Item 2', price: 50 });// 使用信用卡支付
cart.checkout(new CreditCardStrategy('1234-5678-9012-3456', 'John Doe', '123', '12/25'));// 使用 PayPal 支付
cart.checkout(new PayPalStrategy('john@example.com', 'password'));// 使用 JavaScript 函数作为策略
const paymentStrategies = {creditCard: function(amount) {console.log(`Paying ${amount} using Credit Card`);},paypal: function(amount) {console.log(`Paying ${amount} using PayPal`);},bitcoin: function(amount) {console.log(`Paying ${amount} using Bitcoin`);}
};function processPayment(amount, strategy) {return paymentStrategies[strategy](amount);
}processPayment(150, 'creditCard'); // "Paying 150 using Credit Card"
processPayment(150, 'paypal'); // "Paying 150 using PayPal"
4.3 命令模式
命令模式将请求封装为对象,使用者和发送者解耦。
// 命令接口
class Command {execute() {throw new Error('execute method must be implemented');}undo() {throw new Error('undo method must be implemented');}
}// 接收者
class Light {constructor() {this.isOn = false;}turnOn() {this.isOn = true;console.log('Light is now ON');}turnOff() {this.isOn = false;console.log('Light is now OFF');}
}// 具体命令
class TurnOnCommand extends Command {constructor(light) {super();this.light = light;}execute() {this.light.turnOn();}undo() {this.light.turnOff();}
}class TurnOffCommand extends Command {constructor(light) {super();this.light = light;}execute() {this.light.turnOff();}undo() {this.light.turnOn();}
}// 调用者
class RemoteControl {constructor() {this.commands = [];this.history = [];}setCommand(slot, command) {this.commands[slot] = command;}pressButton(slot) {const command = this.commands[slot];if (command) {command.execute();this.history.push(command);}}pressUndoButton() {const command = this.history.pop();if (command) {command.undo();}}
}// 客户端代码
const light = new Light();
const turnOn = new TurnOnCommand(light);
const turnOff = new TurnOffCommand(light);const remote = new RemoteControl();
remote.setCommand(0, turnOn);
remote.setCommand(1, turnOff);remote.pressButton(0); // "Light is now ON"
remote.pressButton(1); // "Light is now OFF"
remote.pressUndoButton(); // "Light is now ON"
4.4 迭代器模式
迭代器模式提供一种顺序访问集合元素的方法,而不暴露内部表示。
// 自定义迭代器
class ArrayIterator {constructor(array) {this.array = array;this.index = 0;}hasNext() {return this.index < this.array.length;}next() {return this.hasNext() ? this.array[this.index++] : null;}
}// 可迭代集合
class Collection {constructor() {this.items = [];}addItem(item) {this.items.push(item);}getIterator() {return new ArrayIterator(this.items);}
}// 使用迭代器
const collection = new Collection();
collection.addItem('Item 1');
collection.addItem('Item 2');
collection.addItem('Item 3');const iterator = collection.getIterator();
while (iterator.hasNext()) {console.log(iterator.next());
}// ES6 实现迭代器协议和可迭代协议
class NumberRange {constructor(start, end) {this.start = start;this.end = end;}// 使对象可迭代[Symbol.iterator]() {let current = this.start;const end = this.end;// 迭代器对象return {next() {if (current <= end) {return { value: current++, done: false };} else {return { done: true };}}};}
}// 使用 for...of 遍历
for (const num of new NumberRange(1, 5)) {console.log(num); // 1, 2, 3, 4, 5
}
4.5 中介者模式
中介者模式通过引入中介对象来减少对象之间的直接通信,降低耦合度。
// 中介者
class ChatRoom {constructor() {this.users = {};}register(user) {this.users[user.name] = user;user.chatRoom = this;}send(message, from, to) {if (to) {// 私聊消息this.users[to].receive(message, from);} else {// 广播消息for (const key in this.users) {if (this.users[key] !== from) {this.users[key].receive(message, from);}}}}
}// 同事类
class User {constructor(name) {this.name = name;this.chatRoom = null;}send(message, to) {this.chatRoom.send(message, this, to);}receive(message, from) {console.log(`${from.name} to ${this.name}: ${message}`);}
}// 使用
const chatRoom = new ChatRoom();const john = new User('John');
const jane = new User('Jane');
const bob = new User('Bob');chatRoom.register(john);
chatRoom.register(jane);
chatRoom.register(bob);john.send('Hi everyone!');
jane.send('Hey John!', 'John');
bob.send('Hello!');
5. 实际应用案例
5.1 表单验证系统
结合了策略模式和装饰器模式。
// 验证策略
const validators = {required: (value) => value.trim() !== '' ? null : 'This field is required',minLength: (value, min) => value.length >= min ? null : `Must be at least ${min} characters`,maxLength: (value, max) => value.length <= max ? null : `Cannot exceed ${max} characters`,email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? null : 'Invalid email format',pattern: (value, regex) => regex.test(value) ? null : 'Invalid format'
};// 表单验证器类
class FormValidator {constructor() {this.validations = {};}// 添加验证规则addValidation(field, validations) {this.validations[field] = validations;}
结语
感谢您的阅读!期待您的一键三连!欢迎指正!