一、继承方法概述
二、原型链
不了解原型链的请先看:一文看懂原型链
三、继承方法
- 原型链继承
原型链继承即采用定义子构造函数的prototype指向父类的实例的方法
本质是:父公有+父私有 ---> 子公有
function Parent(){
this.color = ['red','green'];
}
function Child(){
}
Child.prototype = new Parent();//父类的公有和私有属性被继承为子类的公有属性
var c = new Child();
注意:此时原型链并不完整,Child.prototype = Parent实例,但Parent实例的constructor却指向Parent构造函数,因此c.constructor指向Parent构造函数。
- 借助构造函数(经典继承或伪造对象)
借助构造函数即只在构造函数中使用call(this)函数继承。
本质:父私有---> 子私有
function Parent(){
this.color = ['red','green'];
}
Parent.prototype.showColor = function(){
console.log(this.color);
}
function Child(){
Parent.call(this); // 父类私有属性被继承为子类私有属性
}
var c = new Child();
c.color //['red','green']
c.showColor() //undefined
- 组合继承
组合继承即同时采用原型链和构造函数继承
本质:父公有+父私有--->子公有, 父私有--->子私有(私有覆盖公有)
function Parent(){
this.color = ['red','green'];
}
Parent.prototype.showColor = function(){
console.log(this.color)
}
Parent.prototype.name = 'bigP';
function Child(){
Parent.call(this); //第二次调用父类构造函数
}
Child.prototype = new Parent() //第一次调用父类构造函数
var c = new Child()
经过组合继承,子类的结构为:子类公有包括:父公有+父私有,子类私有包括:父私有,由于父私有属性和方法分别存在于子类的公有和私有属性,根据原型链属性查找的特性,私有属性优先于公有属性,因此子类公有属性中的父私有属性被覆盖。
那么为什么会同时存中两个父私有属性呢?这要从new 构造函数的实际过程讲起。
new Parent()的简要过程如下:
- 创建一个Object对象:var obj = Object()
- 将新建的对象的[[prototype]]即__proto__指向new 后面的构造函数的prototype: obj.__proto__ = Parent.prototype
- 将构造函数中的this指向新建的对象:Parent.call(obj, 传入的对象数据) :Parent.call(obj)
- 若函数中有显式返回其他对象(其他类型忽略),则直接返回其他对象,否则返回新建对象:return obj (即返回实例)
由上述过程可知,在组合继承中使用了两次Parent.call(),因此原型对象和构造函数同时继承了父类的私有变量。
- 原型式继承
原型式继承是将原型链继承用函数包装起来
本质:(还是原型链继承)父公有+父私有--->子公有
//o为被继承的父类对象
//区别于原型链继承:父类对象可以用对象字面量定义{},也可以用构造函数new Parent()
function object(o){
function F(){}
F.prototype = o;
return new F();
}
var c = object(o)
由于原型式继承只是使用了prototype,实际和原型链继承是一样的效果,只是父类对象不仅可以是构造函数创建的实例,也可用对象字面量定义,只是两种方法的原型链不同。
- 寄生式继承
寄生式继承是在原型式继承的基础上用函数封装并添加子类私有属性的继承方法,
本质:父公有+父私有--->子公有,新增属性--->子私有
function createChild(original){
var child = object(original); //使用原型式继承的函数
child.name = 'newChild'; //添加子类私有属性和方法
return child;
}
var parent = {
color: ['red','green']
};
var c = createChild(parent);
- 寄生组合式继承
寄生组合式继承同样是在原型式继承的基础上用函数封装,但是通过原型链继承父类的公有属性,通过构造函数继承父类的私有属性。本质:父公有--->子公有,父私有--->子私有。
function inheritePrototype(Child, Parent){
var childProto = object(Parent.prototype);
childProto.constructor = Child
Child.prototype = childProto;
}
function Parent(){
this.color = ['red','green'];
}
Parent.prototype.showColor = function(){
console.log(this.color);
}
function Child(){
Parent.call(this); // 父类的私有属性被继承为子类的私有属性
}
inheritePtototype(Child,Parent); // 父类的公有属性被继承为子类的公有属性
在继承父类公有属性的函数中,本质是创建了一个空的构造函数F并直接指向Parent.prototype,生成一个只包含父类公有属性的实例对象,然后将已经继承了父类私有属性的构造函数指向该实例对象。