夯基础之手撕JavaScript继承详解
本文将介绍JavaScript中继承的几种实现方式,并通过手写代码的方式,从底层原理上详解每种实现方式的具体过程。
一、JavaScript中继承的实现方式
1. 原型链继承
通过将子类的原型指向父类实例来实现继承。
function Parent() {}
function Child() {}
Child.prototype = new Parent();
原型链继承的缺点在于:
- Child实例的所有属性和方法都会被继承,包括无意义的父类属性。
- 当Child的实例修改继承属性时,会影响到原型链上的所有实例。
2. 构造函数继承
在子类中通过调用父类的构造函数来获取父类实例上的属性和方法,同时将父类属性和方法绑定到子类的实例上。
function Parent() {
this.name = 'parent';
}
function Child() {
Parent.call(this);
this.age = 18;
}
构造函数继承的缺点在于:
- 每次创建的子类实例都会创建一份父类实例上的属性和方法。
- 无法继承父类原型上的属性和方法。
3. 组合继承
将原型链继承和构造函数继承结合起来,通过父类构造函数绑定属性和方法到子类实例上,通过子类原型继承父类原型上的属性和方法来实现继承。
function Parent() {
this.name = 'parent';
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Child() {
Parent.call(this);
this.age = 18;
}
Child.prototype = new Parent();
组合继承的缺点在于:
- 在使用new
关键字创建Child实例时,会调用2次父类构造函数,导致子类实例上出现了两份相同的属性和方法。
4. 原型式继承
通过借助已有对象的能力来创建新对象,类似于JavaScript中的浅拷贝。
let person = {
name: 'Tom',
friends: ['Jerry', 'Bob']
};
let anotherPerson = Object.create(person);
原型式继承的缺点在于:
- 会存在有意义或无意义的共享引用问题。
- 无法进行属性和方法的复用。
5. 寄生式继承
在工厂模式或构造函数模式的基础上,在函数内部创建一个仅用于封装继承过程的函数,最终返回这个新函数,从而达到对原型式继承对进一步封装的效果。
function object(o) {
function F(){}
F.prototype = o;
return new F()
}
function createAnother(original) {
let clone = object(original);
clone.sayHi = function() {
console.log('hi');
}
return clone;
}
let person = {
name: 'Tom',
friends: ['Jerry', 'Bob']
};
let anotherPerson = createAnother(person);
寄生式继承的缺点在于:
- 无法进行属性和方法的复用。
- 与构造函数模式一样,每次创建实例都会创建一份方法。
6. 寄生组合式继承
通过组合继承和寄生式继承的方式来实现继承,避免了组合继承父类构造函数被多次调用和寄生式继承无法进行属性和方法复用的缺点。
function inheritPrototype(SubType, SuperType) {
let prototype = Object.create(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
}
function Parent() {
this.name = 'parent';
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child() {
Parent.call(this);
this.age = 18;
}
inheritPrototype(Child, Parent);
二、示例说明
1. 原型链继承示例
function Animal() {
this.legsNum = 4;
}
function Cat() {}
Cat.prototype = new Animal();
let cat = new Cat();
console.log(cat.legsNum); // 4
通过将Cat的原型指向一个Animal实例,实现了Cat对Animal实例属性和方法的继承。
2. 寄生组合式继承示例
function Mammal(name) {
this.name = name;
}
Mammal.prototype.sayName = function() {
console.log(this.name);
}
function Dog(name, age) {
Mammal.call(this, name);
this.age = age;
}
inheritPrototype(Dog, Mammal);
Dog.prototype.sayAge = function() {
console.log(this.age);
}
let dog = new Dog('小黑', 3);
dog.sayName(); // 小黑
dog.sayAge(); // 3
通过将Mammal构造函数中的属性和方法绑定到Dog实例上,并通过寄生式继承Mammal的原型属性和方法到Dog的原型上,实现了对Mammal的构造函数和原型上的属性和方法进行了复用,同时达到了继承的目的。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:夯基础之手撕javascript继承详解 - Python技术站