跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
javascript:第九章面向对象编程
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第九章 面向对象编程 ====== ===== 本章目标 ===== * 理解面向对象编程(OOP)的核心概念 * 掌握JavaScript中的构造函数和原型 * 深入理解ES6类的语法和特性 * 学会使用封装、继承和多态 * 掌握私有字段和静态成员的使用 ===== 9.1 面向对象编程基础 ===== ==== 9.1.1 什么是面向对象编程 ==== 面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它将程序组织为对象的集合,每个对象包含数据(属性)和操作数据的方法。 **OOP的四大特性:** * **封装**:将数据和操作数据的方法绑定在一起,隐藏内部实现细节 * **继承**:子类可以继承父类的属性和方法,实现代码复用 * **多态**:同一操作作用于不同的对象可以有不同的解释 * **抽象**:提取事物的本质特征,忽略非本质细节 ==== 9.1.2 JavaScript中的OOP ==== JavaScript是一门基于原型的面向对象语言,与其他基于类的语言(如Java、C++)有所不同。 <code javascript> // 基于原型的对象创建 const person = { name: '张三', age: 25, greet: function() { console.log('你好,我是' + this.name); } }; person.greet(); // 你好,我是张三 </code> ===== 9.2 构造函数与原型 ===== ==== 9.2.1 构造函数 ==== 构造函数是用于创建和初始化对象的函数。按照约定,构造函数名首字母大写。 <code javascript> function Person(name, age) { this.name = name; this.age = age; this.greet = function() { console.log('你好,我是' + this.name); }; } const person1 = new Person('张三', 25); const person2 = new Person('李四', 30); person1.greet(); // 你好,我是张三 person2.greet(); // 你好,我是李四 // 每个实例都有自己的greet方法,占用额外内存 console.log(person1.greet === person2.greet); // false </code> ==== 9.2.2 原型(Prototype) ==== 每个JavaScript对象都有一个原型对象,对象可以从原型继承属性和方法。使用原型可以节省内存,因为所有实例共享同一个方法。 <code javascript> function Person(name, age) { this.name = name; this.age = age; } // 将方法定义在原型上 Person.prototype.greet = function() { console.log('你好,我是' + this.name); }; Person.prototype.getAge = function() { return this.age; }; const person1 = new Person('张三', 25); const person2 = new Person('李四', 30); // 所有实例共享原型上的方法 console.log(person1.greet === person2.greet); // true person1.greet(); // 你好,我是张三 console.log(person2.getAge()); // 30 </code> ==== 9.2.3 原型链 ==== 当访问对象的属性或方法时,JavaScript会沿着原型链向上查找,直到找到该属性或到达原型链的顶端(null)。 <code javascript> // 原型链示例 function Animal(name) { this.name = name; } Animal.prototype.speak = function() { console.log(this.name + '发出声音'); }; function Dog(name, breed) { Animal.call(this, name); // 调用父类构造函数 this.breed = breed; } // 建立原型链 Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.speak = function() { console.log(this.name + '汪汪叫'); }; const dog = new Dog('旺财', '金毛'); dog.speak(); // 旺财汪汪叫 // 检查原型链 console.log(dog instanceof Dog); // true console.log(dog instanceof Animal); // true console.log(dog instanceof Object); // true </code> ===== 9.3 ES6类(Class) ===== ==== 9.3.1 类的基本语法 ==== ES6引入了class关键字,提供了更简洁、更清晰的面向对象编程语法。class本质上仍是原型的语法糖。 <code javascript> class Person { // 构造函数 constructor(name, age) { this.name = name; this.age = age; } // 实例方法 greet() { console.log(`你好,我是${this.name}`); } getInfo() { return `${this.name},${this.age}岁`; } } const person = new Person('张三', 25); person.greet(); // 你好,我是张三 console.log(person.getInfo()); // 张三,25岁 </code> ==== 9.3.2 类的继承 ==== <code javascript> class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name}发出声音`); } move() { console.log(`${this.name}在移动`); } } class Dog extends Animal { constructor(name, breed) { super(name); // 调用父类构造函数 this.breed = breed; } // 重写父类方法 speak() { console.log(`${this.name}汪汪叫`); } // 子类特有方法 fetch() { console.log(`${this.name}去捡球`); } } class Cat extends Animal { speak() { console.log(`${this.name}喵喵叫`); } climb() { console.log(`${this.name}在爬树`); } } const dog = new Dog('旺财', '金毛'); const cat = new Cat('咪咪'); dog.speak(); // 旺财汪汪叫 dog.move(); // 旺财在移动 dog.fetch(); // 旺财去捡球 cat.speak(); // 咪咪喵喵叫 cat.climb(); // 咪咪在爬树 </code> ==== 9.3.3 super关键字 ==== super关键字用于调用父类的方法或构造函数。 <code javascript> class Rectangle { constructor(width, height) { this.width = width; this.height = height; } getArea() { return this.width * this.height; } getInfo() { return `矩形:${this.width} x ${this.height}`; } } class Square extends Rectangle { constructor(side) { super(side, side); // 调用父类构造函数 this.side = side; } getInfo() { // 调用父类的getInfo方法 return `正方形:边长${this.side},继承自${super.getInfo()}`; } } const square = new Square(5); console.log(square.getArea()); // 25 console.log(square.getInfo()); // 正方形:边长5,继承自矩形:5 x 5 </code> ===== 9.4 封装与访问控制 ===== ==== 9.4.1 私有字段(ES2022) ==== ES2022引入了真正的私有字段,使用#前缀表示,只能在类的内部访问。 <code javascript> class BankAccount { // 私有字段 #balance = 0; #accountNumber; constructor(accountNumber, initialBalance) { this.#accountNumber = accountNumber; this.#balance = initialBalance; } // 公共方法 deposit(amount) { if (amount > 0) { this.#balance += amount; console.log(`存入${amount}元,当前余额:${this.#balance}元`); } } withdraw(amount) { if (amount > 0 && amount <= this.#balance) { this.#balance -= amount; console.log(`取出${amount}元,当前余额:${this.#balance}元`); } else { console.log('余额不足'); } } getBalance() { return this.#balance; } // 私有方法 #validateAmount(amount) { return amount > 0 && typeof amount === 'number'; } } const account = new BankAccount('123456', 1000); account.deposit(500); // 存入500元,当前余额:1500元 account.withdraw(200); // 取出200元,当前余额:1300元 console.log(account.getBalance()); // 1300 // 以下都会报错 // console.log(account.#balance); // SyntaxError // account.#validateAmount(100); // SyntaxError </code> ==== 9.4.2 Getter和Setter ==== Getter和Setter用于控制属性的访问和赋值。 <code javascript> class Temperature { constructor(celsius) { this._celsius = celsius; } // Getter:摄氏度 get celsius() { return this._celsius; } // Setter:摄氏度 set celsius(value) { if (value < -273.15) { throw new Error('温度不能低于绝对零度'); } this._celsius = value; } // Getter:华氏度 get fahrenheit() { return this._celsius * 9 / 5 + 32; } // Setter:华氏度 set fahrenheit(value) { this._celsius = (value - 32) * 5 / 9; } // Getter:开尔文 get kelvin() { return this._celsius + 273.15; } } const temp = new Temperature(25); console.log(temp.celsius); // 25 console.log(temp.fahrenheit); // 77 temp.fahrenheit = 86; console.log(temp.celsius); // 30 </code> ===== 9.5 静态成员 ===== ==== 9.5.1 静态方法和属性 ==== 静态方法和属性属于类本身,而不是类的实例。使用static关键字定义。 <code javascript> class MathUtils { // 静态属性 static PI = 3.14159; // 静态方法 static add(a, b) { return a + b; } static subtract(a, b) { return a - b; } static multiply(a, b) { return a * b; } static circleArea(radius) { return this.PI * radius * radius; } } // 直接通过类调用 console.log(MathUtils.PI); // 3.14159 console.log(MathUtils.add(5, 3)); // 8 console.log(MathUtils.circleArea(5)); // 78.53975 // 不能通过实例调用 const utils = new MathUtils(); // utils.add(1, 2); // TypeError: utils.add is not a function </code> ==== 9.5.2 静态块(ES2022) ==== ES2022引入了静态块,用于执行类的静态初始化逻辑。 <code javascript> class Database { static connection = null; static config = {}; // 静态块 static { console.log('执行静态初始化块'); this.config = { host: 'localhost', port: 3306, database: 'myapp' }; } static connect() { if (!this.connection) { this.connection = `连接到${this.config.host}:${this.config.port}`; } return this.connection; } } console.log(Database.connect()); // 执行静态初始化块 → 连接到localhost:3306 </code> ===== 9.6 多态 ===== 多态允许子类以不同的方式实现父类的方法。 <code javascript> class Shape { getArea() { throw new Error('子类必须实现getArea方法'); } getPerimeter() { throw new Error('子类必须实现getPerimeter方法'); } describe() { return `面积:${this.getArea()},周长:${this.getPerimeter()}`; } } class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } getArea() { return this.width * this.height; } getPerimeter() { return 2 * (this.width + this.height); } } class Circle extends Shape { constructor(radius) { super(); this.radius = radius; } getArea() { return Math.PI * this.radius * this.radius; } getPerimeter() { return 2 * Math.PI * this.radius; } } class Triangle extends Shape { constructor(a, b, c) { super(); this.a = a; this.b = b; this.c = c; } getArea() { const s = (this.a + this.b + this.c) / 2; return Math.sqrt(s * (s - this.a) * (s - this.b) * (s - this.c)); } getPerimeter() { return this.a + this.b + this.c; } } // 使用多态 const shapes = [ new Rectangle(5, 3), new Circle(5), new Triangle(3, 4, 5) ]; shapes.forEach(function(shape) { console.log(shape.describe()); }); </code> ===== 9.7 抽象类与接口 ===== ==== 9.7.1 模拟抽象类 ==== JavaScript没有内置的抽象类,但可以通过抛出错误来模拟。 <code javascript> class Animal { constructor(name) { if (new.target === Animal) { throw new Error('Animal是抽象类,不能直接实例化'); } this.name = name; } speak() { throw new Error('子类必须实现speak方法'); } move() { console.log(`${this.name}在移动`); } } // const animal = new Animal('test'); // Error: Animal是抽象类,不能直接实例化 class Dog extends Animal { speak() { console.log(`${this.name}汪汪叫`); } } const dog = new Dog('旺财'); dog.speak(); // 旺财汪汪叫 </code> ==== 9.7.2 Mixin模式 ==== Mixin是一种代码复用模式,用于在不使用多重继承的情况下共享功能。 <code javascript> // 定义Mixin const Flyable = { fly() { console.log(`${this.name}在飞翔`); }, land() { console.log(`${this.name}降落了`); } }; const Swimmable = { swim() { console.log(`${this.name}在游泳`); }, dive() { console.log(`${this.name}潜入水中`); } }; // 应用Mixin的辅助函数 function mixin(target, ...sources) { Object.assign(target.prototype, ...sources); } class Bird { constructor(name) { this.name = name; } } mixin(Bird, Flyable); class Fish { constructor(name) { this.name = name; } } mixin(Fish, Swimmable); class Duck { constructor(name) { this.name = name; } } mixin(Duck, Flyable, Swimmable); const bird = new Bird('麻雀'); bird.fly(); // 麻雀在飞翔 const duck = new Duck('唐老鸭'); duck.fly(); // 唐老鸭在飞翔 duck.swim(); // 唐老鸭在游泳 </code> ===== 9.8 实战案例 ===== ==== 9.8.1 设计一个组件系统 ==== <code javascript> class Component { constructor(props = {}) { this.props = props; this.state = {}; this.element = null; } setState(newState) { this.state = { ...this.state, ...newState }; this.render(); } mount(container) { this.element = this.render(); container.appendChild(this.element); } render() { throw new Error('子类必须实现render方法'); } } class Button extends Component { constructor(props) { super(props); this.state = { clicked: 0 }; } render() { const button = document.createElement('button'); button.textContent = `${this.props.label} (点击${this.state.clicked}次)`; button.onclick = () => { this.setState({ clicked: this.state.clicked + 1 }); if (this.props.onClick) { this.props.onClick(); } }; return button; } } class Input extends Component { render() { const input = document.createElement('input'); input.type = this.props.type || 'text'; input.placeholder = this.props.placeholder || ''; input.onchange = (e) => { if (this.props.onChange) { this.props.onChange(e.target.value); } }; return input; } } // 使用 // const button = new Button({ label: '点击我', onClick: () => console.log('clicked') }); // button.mount(document.body); </code> ===== 本章习题 ===== ==== 基础练习 ==== **练习1:类和对象** 创建一个Car类,包含品牌、型号、年份属性,以及启动、停止、获取信息的方法。 **练习2:继承** 创建ElectricCar类继承Car,添加电池容量属性和充电方法。 **练习3:封装** 创建一个Counter类,使用私有字段存储计数值,提供增加、减少、重置和获取值的方法。 ==== 进阶练习 ==== **练习4:多态设计** 设计一个图形系统,包含Shape抽象类,以及Circle、Rectangle、Triangle等具体类,实现面积和周长的计算。 **练习5:Mixin实现** 实现一个EventEmitter Mixin,使任何类都具有事件发布订阅能力。 <code javascript> const EventEmitter = { on(event, callback) { /* 实现 */ }, emit(event, data) { /* 实现 */ }, off(event, callback) { /* 实现 */ } }; </code> **练习6:设计模式应用** 使用单例模式设计一个配置管理器类,确保整个应用中只有一个配置实例。 ==== 思考题 ==== 1. JavaScript的class和传统的面向对象语言(如Java)有什么本质区别? 2. 私有字段(#)和下划线前缀(_)的私有约定有什么区别? 3. 什么时候应该使用静态方法? 4. 原型继承和类继承各有什么优缺点? ===== 参考答案 ===== **练习3答案:** <code javascript> class Counter { #count = 0; increment() { this.#count++; } decrement() { if (this.#count > 0) { this.#count--; } } reset() { this.#count = 0; } getValue() { return this.#count; } } const counter = new Counter(); counter.increment(); counter.increment(); console.log(counter.getValue()); // 2 </code> **练习6答案:** <code javascript> class ConfigManager { static #instance = null; #config = {}; constructor() { if (ConfigManager.#instance) { return ConfigManager.#instance; } ConfigManager.#instance = this; } static getInstance() { if (!ConfigManager.#instance) { ConfigManager.#instance = new ConfigManager(); } return ConfigManager.#instance; } set(key, value) { this.#config[key] = value; } get(key) { return this.#config[key]; } } const config1 = ConfigManager.getInstance(); const config2 = ConfigManager.getInstance(); console.log(config1 === config2); // true </code> ===== 小结 ===== 本章我们学习了JavaScript面向对象编程的核心概念: * **OOP基础**:封装、继承、多态、抽象 * **构造函数与原型**:理解JavaScript的对象创建机制 * **ES6类**:更清晰的面向对象语法 * **访问控制**:私有字段、Getter/Setter * **静态成员**:类级别的属性和方法 * **设计模式**:抽象类、Mixin、单例模式 掌握面向对象编程对于构建大型、可维护的JavaScript应用至关重要。
javascript/第九章面向对象编程.txt
· 最后更改:
2026/02/03 22:33
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部