Overriding object methods
Basic Concepts of Method Overriding
In JavaScript, method overriding refers to a subclass replacing a method already defined in the parent class to implement behavior specific to the subclass. This mechanism is an important manifestation of polymorphism in object-oriented programming, allowing different objects to respond differently to the same message.
class Animal {
makeSound() {
console.log('Some generic animal sound');
}
}
class Dog extends Animal {
makeSound() {
console.log('Bark! Bark!');
}
}
const myDog = new Dog();
myDog.makeSound(); // Output: Bark! Bark!
Prototype Chain and Method Overriding
JavaScript implements inheritance through the prototype chain. Method overriding essentially creates a method with the same name on the subclass's prototype, thereby shadowing the method on the parent class's prototype:
function Animal() {}
Animal.prototype.makeSound = function() {
console.log('Generic sound');
};
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// Method overriding
Dog.prototype.makeSound = function() {
console.log('Woof!');
};
const dog = new Dog();
dog.makeSound(); // Output: Woof!
Using the super
Keyword
In ES6 class syntax, the super
keyword can be used to call the overridden method of the parent class:
class Bird {
fly() {
console.log('Flying high');
}
}
class Penguin extends Bird {
fly() {
if (this.canFly) {
super.fly(); // Call the parent class's fly method
} else {
console.log('Sorry, I can\'t fly');
}
}
constructor() {
super();
this.canFly = false;
}
}
const penguin = new Penguin();
penguin.fly(); // Output: Sorry, I can't fly
Practical Application Scenarios of Method Overriding
Method overriding is widely used in framework development and everyday programming:
- UI Component Customization:
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();
// Output:
// Default button click
// Form submitted
- Character Behavior in Game Development:
class Character {
attack() {
return 10; // Base attack power
}
}
class Warrior extends Character {
attack() {
return super.attack() * 1.5; // Warrior attack bonus
}
}
class Mage extends Character {
attack() {
return super.attack() + 15; // Mage magic attack
}
}
Difference Between Method Overriding and Property Shadowing
Method overriding is different from property shadowing, where a new value simply overwrites the property:
class Parent {
value = 1;
getValue() {
return this.value;
}
}
class Child extends Parent {
value = 2; // Property shadowing
getValue() {
return this.value * 2; // Method overriding
}
}
const child = new Child();
console.log(child.value); // 2 (Property shadowing)
console.log(child.getValue()); // 4 (Method overriding)
Dynamic Method Overriding
JavaScript allows dynamic method overriding at runtime:
class DynamicExample {
logMessage() {
console.log('Original message');
}
}
const instance = new DynamicExample();
// Original method
instance.logMessage(); // Output: Original message
// Dynamically override the method
instance.logMessage = function() {
console.log('Dynamically replaced message');
};
instance.logMessage(); // Output: Dynamically replaced message
Considerations for Method Overriding
- Maintain Consistent Method Signatures:
class ApiClient {
fetchData(url, options = {}) {
// Base implementation
}
}
class AuthApiClient extends ApiClient {
// Incorrect overriding - parameter mismatch
fetchData(url) {
// Missing options parameter
}
// Correct overriding
fetchData(url, options = {}) {
options.headers = options.headers || {};
options.headers.Authorization = 'Bearer token';
return super.fetchData(url, options);
}
}
- Avoid Excessive Overriding:
class OverrideExample {
// Too many small method overrides can make maintenance difficult
method1() { /*...*/ }
method2() { /*...*/ }
method3() { /*...*/ }
}
class BadPractice extends OverrideExample {
method1() { /* Completely different implementation */ }
method2() { /* Completely different implementation */ }
method3() { /* Completely different implementation */ }
// In such cases, consider refactoring instead of inheritance
}
Advanced Method Overriding Patterns
- Decorator Pattern:
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);
// Output:
// Calling add with [2, 3]
// Called add, returned 5
- Strategy Pattern:
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
Method Overriding and Performance Considerations
Frequent method overriding can impact performance, especially in hot code paths:
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;
}
}
Browser Compatibility and Method Overriding
Compatibility issues to note in older JavaScript environments:
// Compatibility writing for ES5 and below
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); // Explicitly call the parent class method
console.log('New way');
};
var instance = new NewWay();
instance.method();
// Output:
// Old way
// New way
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:JavaScript核心知识点
下一篇:对象属性检测