Implementation of inheritance
The Concept of Inheritance
Inheritance is one of the core concepts of object-oriented programming, allowing an object to acquire the properties and methods of another object. In JavaScript, inheritance is primarily implemented through the prototype chain. After ES6, more intuitive inheritance can also be achieved using the class
syntactic sugar.
Prototypal Inheritance
Prototypal inheritance is the most basic form of inheritance, achieved by setting the child class's prototype to an instance of the parent class.
function Parent() {
this.name = 'parent';
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child() {
this.age = 10;
}
// Key step: Set Child's prototype to an instance of Parent
Child.prototype = new Parent();
const child1 = new Child();
child1.sayName(); // Output: parent
console.log(child1.age); // Output: 10
Disadvantages of this approach:
- All child instances share the reference properties of the parent instance.
- Cannot pass arguments to the parent constructor.
Constructor Inheritance
Constructor inheritance is achieved by calling the parent constructor within the child constructor.
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
function Child(name, age) {
Parent.call(this, name); // Key step: Call the parent constructor
this.age = age;
}
const child1 = new Child('Tom', 10);
console.log(child1.name); // Output: Tom
console.log(child1.age); // Output: 10
Advantages:
- Solves the issue of shared reference properties in prototypal inheritance.
- Allows passing arguments to the parent constructor.
Disadvantages:
- Cannot inherit methods from the parent prototype.
- The parent constructor is called every time an instance is created.
Combination Inheritance
Combination inheritance combines the advantages of prototypal and constructor inheritance.
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name); // Second call to Parent
this.age = age;
}
Child.prototype = new Parent(); // First call to Parent
Child.prototype.constructor = Child;
const child1 = new Child('Tom', 10);
child1.sayName(); // Output: Tom
console.log(child1.age); // Output: 10
Advantages:
- Can inherit both instance and prototype properties from the parent.
- Allows passing arguments.
- Reference properties are not shared.
Disadvantages:
- The parent constructor is called twice.
Prototypal Pattern Inheritance
Prototypal pattern inheritance creates new objects based on existing objects, similar to the implementation of Object.create()
.
function createObject(o) {
function F() {}
F.prototype = o;
return new F();
}
const parent = {
name: 'parent',
colors: ['red', 'blue'],
sayName: function() {
console.log(this.name);
}
};
const child = createObject(parent);
child.name = 'child';
child.sayName(); // Output: child
In ES5, the same functionality can be achieved directly using Object.create()
.
Parasitic Inheritance
Parasitic inheritance enhances objects based on prototypal inheritance.
function createAnother(original) {
const clone = Object.create(original);
clone.sayHi = function() {
console.log('hi');
};
return clone;
}
const parent = {
name: 'parent',
colors: ['red', 'blue']
};
const child = createAnother(parent);
child.sayHi(); // Output: hi
Parasitic Combination Inheritance
Parasitic combination inheritance is currently the most ideal inheritance approach, solving the issue of calling the constructor twice in combination inheritance.
function inheritPrototype(child, parent) {
const prototype = Object.create(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent);
const child1 = new Child('Tom', 10);
child1.sayName(); // Output: Tom
console.log(child1.age); // Output: 10
ES6 Class Inheritance
ES6 introduced the class
syntactic sugar, making inheritance more intuitive.
class Parent {
constructor(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // Call the parent constructor
this.age = age;
}
sayAge() {
console.log(this.age);
}
}
const child1 = new Child('Tom', 10);
child1.sayName(); // Output: Tom
child1.sayAge(); // Output: 10
Implementing Multiple Inheritance
JavaScript does not natively support multiple inheritance, but it can be simulated using the Mixin pattern.
class A {
methodA() {
console.log('method A');
}
}
class B {
methodB() {
console.log('method B');
}
}
class C {
constructor() {
Object.assign(this, new A());
Object.assign(this, new B());
}
methodC() {
console.log('method C');
}
}
const c = new C();
c.methodA(); // Output: method A
c.methodB(); // Output: method B
c.methodC(); // Output: method C
Inheritance and Performance Considerations
Prototype chain lookups can impact performance, and deep prototype chains can increase lookup time. In performance-sensitive scenarios, consider defining frequently used methods directly on the object.
function createOptimizedObject() {
const obj = {};
obj.method1 = function() { /* ... */ };
obj.method2 = function() { /* ... */ };
return obj;
}
Inheritance and Design Patterns
Inheritance is applied in various design patterns, such as the Template Method pattern and the Decorator pattern.
// Template Method pattern example
class AbstractClass {
templateMethod() {
this.operation1();
this.operation2();
}
operation1() {
throw new Error('operation1 must be implemented');
}
operation2() {
throw new Error('operation2 must be implemented');
}
}
class ConcreteClass extends AbstractClass {
operation1() {
console.log('Concrete operation 1');
}
operation2() {
console.log('Concrete operation 2');
}
}
const instance = new ConcreteClass();
instance.templateMethod();
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:constructor属性
下一篇:对象拷贝与比较