版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
持续更新中.....
继承一共有六种方式:
分别是:
1. 原型链继承
2. 借用构造函数继承
3. 组合继承
4. 原型式继承
5. 寄生式继承
6. 寄生组合式继承
1. 原型链继承
原型链继承是实现继承的主要方法。
- 基本思想: 利用原型让一个引用类型继承另外一个引用类型的属性和方法。
了解一下构造函数,原型和实例的关系?
- 每个构造函数都有一个原型对象,原型对象都包含指向构造函数的指针(
prototype
),而实例包含了指向原型的指针(__proto__
)
实例的__proto__
属性等于构造函数的prototype
属性
实例 -> 原型 -> 构造函数
原型链的基本概念?
- 如果试图引用对象(实例
instance
)的某个属性,首先会从对象内部开始寻找该属性,直至找不到,然后才会到对象的原型(instance.prototype
)去寻找该属性。 - 如果原型对象指向另一个类型的实例,即
constructor1.prototype = instance2
如果试图引用constructor1
构造的实例instance1
的某个属性p1
:
- 首先会在
instance1
内部找一遍 - 接着在
instance.__proto__
(即constructor1.prototype
)中找一遍,实际上constructor1.prototype
就是instance2
,也就是说在instance2
找到了p1
属性。 - 如果
instance2
还是没有p1
属性,就会持续在instance2.__proto__
(即constructor2.prototype
)中寻找,一直这样下去,直到找到为止。或者找到Object
的原型对象上(null
) - 这样就形成路径了:
instance1-->instance2-->....-->Object.prototype
- 类似链状的结构称为“原型链”
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subProperty = false;
}
// 继承了SuperType 子类型的原型等于父类型的实例。完成原型链继承
SubType.prototype = new SuperType();
// 添加新方法
SubType.prototype.getSubValue(){
return this.subProperty;
}
// 重写父类型中的方法
SubType.prototype.getSuperValue(){
return false;
}
let instance = new SubType();
instance.getSuperValue(); // false
- 上述代码中。第一个方法
getSubValue()
被添加到了SubType
中。而getSuperValue()
是原型链中已经存在的一个方法,但是重写这个方法会屏蔽原来的方法。 - 也就是说当通过
SuperType
的实例调用getSuperValue()
时,还会继续调用原来的那个方法
⚠️通过原型链继承时,不能使用对象字面量创建原型方法。这样会重写原型链。
如:
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue(){
return this.property;
}
function SubType (){
this.subProperty = false;
}
// 继承SuperType
SubType.prototype = new SuperType();
// 使用字面量添加新方法会导致上一条代码无效(即取代)
SubType.prototype = {
getSubValue: function(){
return this.subProprty;
},
someMethod: function(){
return false;
}
}
let instance = new SubType();
instance.getSuperValue(); // 报错
2. 借用构造函数继承
构造函数继承有时候又叫做“伪造对象或经典继承”
- 基本思想: 在子类型构造函数的内部调用父类型构造函数。
- 但是,一般函数只不过是在特定环境中执行代码的对象,因此可以通过使用
apply
,call
方法可以在新创建的对象上执行构造函数。
示例:
function SuperType(){
this.arr = [1,2,3];
}
// 借用构造函数继承
function SubType(){
// 继承SuperType
SuperType.call(this);
}
let instance1 = new SubType();
instance1.arr.push(4);
instance1.arr; // [1,2,3,4]
let instance2 = new SubType();
instance2.arr; // [1,2,3]
- 在上述代码中,在子类型的内部调用了父类型的构造函数
- 使用了
call
方法,实际上是在新创建的SubType
实例环境下调用了SuperType
构造函数 - 这样,就会在新的
SubType
对象上执行SuperType()
函数定义的所有对象初始化代码。结果SubType
的每个实例都会具有SuperType
对象中的属性或方法的副本
这让我想到了,ES6中类的继承为什么要在子类的构造函数中执行super()
方法,就是这个道理。
构造函数继承相对原型链继承的一个优势?
- 可以在子类型的构造函数中向父类型的构造函数传递参数。
示例:
function SuperType(name){
this.name = name;
}
function SubType(){
// 继承 SuperType,同时传递参数
Supertype.call(this, 'Jack');
// 实例属性
this.age = 24;
}
let instance = new SubType();
instance.name; // Jack
instance.age; // 24
3. 组合继承
组合继承有时候又叫“伪经典继承”,是将原型链继承和借用构造函数继承组合到一起的继承。
- 基本思想: 使用原型链实现对原型属性的方法的继承,通过即用构造函数来实现对实例属性的继承。这样即通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
示例:
function SuperType(name){
this.name = name;
this.arr = [1,2,3];
}
SuperType.prototype.sayName = fuction(){
alert(this.name);
}
function SubType(name , age){
// 继承SuperType
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge(){
alert(this.age);
}
let instance1 = new SubType('Jack', 24);
instance1.arr.push(4);
instance1.sayName(); // Jack
instance1.sayAge(); // 24
instance!.arr; // [1,2,3,4]
let instance2 = new SubType("Mary", 23);
instance2.arr; // [1,2,3]
instance2.sayName(); // Mary
instance2.sayAge(); // 23
- 上述代码中,
SuperType
构造函数指定两个属性:name
,arr
。SuperType
的原型定义了sayName()
方法。 SubType
构造函数在调用SuperType
构造函数时传入了name
参数,紧接着定义了sayAge()
方法- 这样就可以让两个不同的
SubType
实例分别拥有自己的属醒(arr
,name
,age
) - 也可以使用相同的方法(
sayName()
,sayAge()
)
4.原型式继承
原型式继承要求必须有一个对象作为另一个对象的基础。
- 基本思想: 借助原型基于已有的对象创建新的对象。
给出函数:
function object(o){
}
通过Object.create()
方法实现原型式继承。
- 这方法接收两个参数
- 一个用作新对象的原型对象(可选)
- 另外一个是一个对象,为新对象添加额外的属性。
示例:
let person = {
name: 'Jack',
age: 24,
friends: [1,2,3]
}
// 继承person
let otherPerson = Object.create(person,{
name: {
value: "Mary"
}
})
alert(otherPerson.name); // Mary
5.寄生式继承
- 基本思想:创造一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。
示例:
function createOther(obj){
let clone =
}