对象方法重写
对象方法重写的基本概念
在JavaScript中,对象方法重写是指子类覆盖父类中已定义的方法,以实现特定于子类的行为。这种机制是面向对象编程中多态性的重要体现,允许不同的对象对同一消息做出不同的响应。
class Animal {
makeSound() {
console.log('Some generic animal sound');
}
}
class Dog extends Animal {
makeSound() {
console.log('Bark! Bark!');
}
}
const myDog = new Dog();
myDog.makeSound(); // 输出: Bark! Bark!
原型链与方法重写
JavaScript通过原型链实现继承,方法重写实际上是在子类的原型上创建同名方法,从而遮蔽父类原型上的方法:
function Animal() {}
Animal.prototype.makeSound = function() {
console.log('Generic sound');
};
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 方法重写
Dog.prototype.makeSound = function() {
console.log('Woof!');
};
const dog = new Dog();
dog.makeSound(); // 输出: Woof!
super关键字的使用
在ES6类语法中,可以使用super关键字调用父类被重写的方法:
class Bird {
fly() {
console.log('Flying high');
}
}
class Penguin extends Bird {
fly() {
if (this.canFly) {
super.fly(); // 调用父类的fly方法
} else {
console.log('Sorry, I can\'t fly');
}
}
constructor() {
super();
this.canFly = false;
}
}
const penguin = new Penguin();
penguin.fly(); // 输出: Sorry, I can't fly
方法重写的实际应用场景
方法重写在框架开发和日常编程中有广泛应用:
- UI组件定制:
class BaseButton {
onClick() {
console.log('Default button click');
}
}
class SubmitButton extends BaseButton {
onClick() {
super.onClick();
this.submitForm();
}
submitForm() {
console.log('Form submitted');
}
}
const submitBtn = new SubmitButton();
submitBtn.onClick();
// 输出:
// Default button click
// Form submitted
- 游戏开发中的角色行为:
class Character {
attack() {
return 10; // 基础攻击力
}
}
class Warrior extends Character {
attack() {
return super.attack() * 1.5; // 战士攻击力加成
}
}
class Mage extends Character {
attack() {
return super.attack() + 15; // 法师魔法攻击
}
}
方法重写与属性遮蔽的区别
方法重写不同于属性遮蔽,后者只是简单地用新值覆盖属性:
class Parent {
value = 1;
getValue() {
return this.value;
}
}
class Child extends Parent {
value = 2; // 属性遮蔽
getValue() {
return this.value * 2; // 方法重写
}
}
const child = new Child();
console.log(child.value); // 2 (属性遮蔽)
console.log(child.getValue()); // 4 (方法重写)
动态方法重写
JavaScript允许运行时动态重写方法:
class DynamicExample {
logMessage() {
console.log('Original message');
}
}
const instance = new DynamicExample();
// 原始方法
instance.logMessage(); // 输出: Original message
// 动态重写方法
instance.logMessage = function() {
console.log('Dynamically replaced message');
};
instance.logMessage(); // 输出: Dynamically replaced message
方法重写的注意事项
- 保持方法签名一致:
class ApiClient {
fetchData(url, options = {}) {
// 基础实现
}
}
class AuthApiClient extends ApiClient {
// 错误的重写 - 参数不一致
fetchData(url) {
// 缺少options参数
}
// 正确的重写
fetchData(url, options = {}) {
options.headers = options.headers || {};
options.headers.Authorization = 'Bearer token';
return super.fetchData(url, options);
}
}
- 避免过度重写:
class OverrideExample {
// 过多的小方法重写会导致维护困难
method1() { /*...*/ }
method2() { /*...*/ }
method3() { /*...*/ }
}
class BadPractice extends OverrideExample {
method1() { /* 完全不同的实现 */ }
method2() { /* 完全不同的实现 */ }
method3() { /* 完全不同的实现 */ }
// 这种情况下应该考虑重构而不是继承
}
高级方法重写模式
- 装饰器模式:
function withLogging(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`Calling ${name} with`, args);
const result = original.apply(this, args);
console.log(`Called ${name}, returned`, result);
return result;
};
return descriptor;
}
class Calculator {
@withLogging
add(a, b) {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3);
// 输出:
// Calling add with [2, 3]
// Called add, returned 5
- 策略模式:
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
process(amount) {
return this.strategy.process(amount);
}
}
class CreditCardStrategy {
process(amount) {
console.log(`Processing $${amount} via Credit Card`);
}
}
class PayPalStrategy {
process(amount) {
console.log(`Processing $${amount} via PayPal`);
}
}
const processor = new PaymentProcessor(new CreditCardStrategy());
processor.process(100); // Processing $100 via Credit Card
processor.strategy = new PayPalStrategy();
processor.process(200); // Processing $200 via PayPal
方法重写与性能考量
频繁的方法重写可能影响性能,特别是在热代码路径中:
class PerformanceExample {
heavyCalculation() {
let result = 0;
for (let i = 0; i < 1e6; i++) {
result += Math.sqrt(i);
}
return result;
}
}
class OptimizedExample extends PerformanceExample {
heavyCalculation() {
if (this.useCache && this.cachedResult) {
return this.cachedResult;
}
const result = super.heavyCalculation();
if (this.useCache) {
this.cachedResult = result;
}
return result;
}
constructor() {
super();
this.useCache = true;
this.cachedResult = null;
}
}
浏览器兼容性与方法重写
在旧版JavaScript环境中需要注意的兼容性问题:
// ES5及以下版本的兼容写法
function OldWay() {}
OldWay.prototype.method = function() {
console.log('Old way');
};
function NewWay() {}
NewWay.prototype = Object.create(OldWay.prototype);
NewWay.prototype.method = function() {
OldWay.prototype.method.call(this); // 显式调用父类方法
console.log('New way');
};
var instance = new NewWay();
instance.method();
// 输出:
// Old way
// New way
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:JavaScript核心知识点
下一篇:对象属性检测