阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 对象方法重写

对象方法重写

作者:陈川 阅读数:3932人阅读 分类: JavaScript

对象方法重写的基本概念

在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

方法重写的实际应用场景

方法重写在框架开发和日常编程中有广泛应用:

  1. 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
  1. 游戏开发中的角色行为
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

方法重写的注意事项

  1. 保持方法签名一致
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);
  }
}
  1. 避免过度重写
class OverrideExample {
  // 过多的小方法重写会导致维护困难
  method1() { /*...*/ }
  method2() { /*...*/ }
  method3() { /*...*/ }
}

class BadPractice extends OverrideExample {
  method1() { /* 完全不同的实现 */ }
  method2() { /* 完全不同的实现 */ }
  method3() { /* 完全不同的实现 */ }
  // 这种情况下应该考虑重构而不是继承
}

高级方法重写模式

  1. 装饰器模式
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
  1. 策略模式
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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌