手写六种继承
devinxiang opened this issue · 0 comments
devinxiang commented
1. 原型链继承
**:利用原型让一个引用类型继承另一个引用类型的属性和方法。
/**
* 1. 原型链继承
* child.prototype = new Parent()
* 把父元素的实例,放大子的 prototype 上面
*/
// 父级元素
function Parent() {
this.name = "Devin";
this.species = ["rich", "poor"];
}
Parent.prototype.getName = function() {
console.log(this.name);
};
// 子元素继承父元素的东西
function Child() {}
Child.prototype = new Parent();
let child1 = new Child();
console.log(child1.name, child1.species);
存在问题
- 原始构造函数里面的应用类型属性被所有实例共享,这个属性一变化都在变化;
- 在 Child 构造原型链继承的时候不能向 Parent 传参
2. 借用构造函数(经典继承)
**:在子类型构造函数的内部调用超类型构造函数,因为函数只不过是在特定环境中执行代码的对象,因此通过使用 apply() 和 call() 方法也可以在(将来)新创建的对象上执行构造函数。
function Parent2() {
this.names = ["kevin", "daisy"];
}
function Child() {
Parent.call(this);
}
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy"]
在新创建的 SubType 实例的环境下调用了 SuperType 构造函数。这样就会在新 SubType 对象上执行 SuperType()函数中定义的所有对象初始化代码。这样,每个实例都会有自己的属性副本了。
优点:
- 避免了引用类型的属性被所有实例共享;
- 可以在 Child 中向 Parent 传参;
缺点:
- 无法复用到 Parent 的 prototype 上面的方法;
- 需要继承的方法都需要在构造函数中定义,每次创建实例都会创建一遍方法。导致函数无法复用,浪费内存。
3. 组合继承
**:
- 通过原型链实现对原型属性和方法的继承
- 通过借用构造函数实现对实例属性的继承
function Parent3(name) {
this.name = name;
this.colors = ["red", "blue"];
}
Parent3.prototype.getName = function() {
console.log(this.name);
};
function Child3(name, age) {
Parent3.call(this, name);
this.age = age;
}
Child3.prototype = new Parent3();
Child3.prototype.constructor = Child3;
var child1 = new Child("Devin", "18");
避免了原型链继承的缺点-实例共享,避免了每个实例的方法不能复用。
4. 原型式继承
**:将传入的对象作为创建的对象的原型
function createObj(o) {
function F(){}
F.prototype = o;
return new F();
}
var person = {
name: 'kevin',
friends: ['daisy', 'kelly']
}
var person1 = createObj(person);
var person2 = createObj(person);
person1.name = 'person1';
console.log(person2.name); // kevin
person1.firends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]
缺点:
- 引用类型的属性值始终会共享;
5. 寄生式继承
思路:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象
function createAnother(original){
var clone = Object.create(original);
clone.sayName = function (){
console.log('hi')
}
return clone;
}
缺点:
- 每次创建对象都会创建一次方法
6. 寄生组合式继承
思路:通过组合寄生的方式继承 prototype 的内容;通过构造函数方式继承实例属性;
// 生成一个新的对象,把继承的属性放在 prototype 上面
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
// 继承 Parent 的 prototype 属性
function proto(Child, Parent){
let prototype = object(Parent.prototype); // 创建对象
prototype.constructor = Child; // 增强对象
Child.prototype = prototype; // 指定对象
}
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
console.log(this.name);
}
function Child(name, age) {
// 构造函数继承
Parent.call(this, name);
this.age = age;
}
proto(Child, Parent);
总结
继承分为
- 继承实例属性,构造函数 this 上面的。实例属性需要单独生成一份;
- 继承公用方法,在被继承的 prototype 上面的;