首先我们先聊一下什么是继承?
简单来说,继承就是让一个没有一些属性和方法的对象拥有一个既有属性又有方法的对象的属性和方法。
那继承又分哪些呢?下面让我为大家讲解一些常用的继承吧。
1.原型对象的继承
function Parent(){
this.name = "zhangshan";
}
Parent.prototype.show = function(){
console.log("111");
}
function Child(){
}
// 浅拷贝
Child.prototype = Parent.prototype;
var t = new Parent();
t.show();//111
console.log(t.name);//zhangshan
var f = new Child();
f.show();//111
console.log(f.name);//undefined
上面是我们采用浅拷贝的方式继承得到的结果,但是如果我们如果Child本身也有一个show的方法呢?它是否会产生覆盖呢?
function Parent(){
this.name = "zhangshan";
}
Parent.prototype.show = function(){
console.log("111");
}
function Child(){
}
// 浅拷贝
Child.prototype = Parent.prototype;
//
Child.prototype.show = function(){
console.log("123");
}
var t = new Parent();
t.show();//123
console.log(t.name);//zhangshan
var f = new Child();
f.show();//123
console.log(f.name);//undefined
结果如我们预测,因为使用浅拷贝但是当Child原型的方法show覆盖了Parent原型show的方法,所以输出结果Parent的show方法值也成为了123;如何解决呢?我们可以通过深拷贝的方式来让他不进行覆盖。
function Parent(){
this.name = "zhangshan";
}
Parent.prototype.show = function(){
console.log("111");
}
function Child(){
}
// 深拷贝:不会被覆盖
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
//
Child.prototype.show = function(){
console.log("123");
}
var t = new Parent();
t.show();//111
console.log(t.name);//zhangshan
var f = new Child();
f.show();//123
console.log(f.name);//undefined
综上所述:我们的原型对象继承1.简单,方便,易操作。2.但是,只能继承原型身上的方法和属性,不能继承构造函数内的方法和属性。
2.原型链继承
function Parent(){
this.name = "zhangshan"
}
Parent.prototype.show = function(){
console.log("哈哈哈")
}
function Child(){
}
Child.prototype = new Parent();
// Parent的实例
var f = new Parent();
f.show();///哈哈哈
console.log(f.name);///zhangshan
// Child的实例
var t = new Child();
t.show();///哈哈哈
console.log(t.name);//zhangshan
很明显我们使用原型链的继承完美的解决了原型对象继承不了构造方法属性和方法的缺陷,但是原型链继承是否也有缺点呢?我再为大家举例一下:
function Parent(n){
this.name = n;
}
Parent.prototype.show = function(){
console.log("哈哈哈")
}
function Child(n){
}
Child.prototype = new Parent("lisi");
// Parent的实例
var f = new Parent();
f.show();///哈哈哈
console.log(f.name);///undefined
// Child的实例
var t = new Child();
t.show();///哈哈哈
console.log(t.name);//lisi
当我们使用传参的方式给Parent的构造函数传入属性的值得时候,我们发现是不可行的,Parent的name属性是undefined,这也就说明了我们的原型链继承1.更加的简单,方便,易操作。 2.不仅可以继承原型身上的方法和属性,而且还可以继承构造函数中的方法和属性。3.但是,不方便传参。
3.构造函数继承
function Parent(s){
this.skill = s;
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(n){
// 利用this的改变
// 在Child中执行Parent的同时,修改this指向,为Child的this
// 因为Child将来被new执行,Child中的this,指向将来Child的实例
Parent.call(this,n);
}
var p = new Parent("zhangshan");
console.log(p.skill);//zhangshan
p.show();//zhangshan
var c = new Child("lisi");
console.log(c.skill);//lisi
c.show();//报错
通过上面例子我们不妨看出构造函数的继承:只能继承构造函数内部的属性或方法,不能继承原型身上的属性或方法。
4.混合继承
function Parent(s){
this.skill = s;
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(n){
Parent.call(this,n);
}
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
console.log("wangwu");
}
var p = new Parent("zhangshan");
p.show();//zhangshan
var c = new Child("lisi");
c.show();//wangwu
console.log(c.skill);//lisi
混合继承:构造函数继承 + 原型继承, 而且他的特点为:1.略复杂。2.既可以继承构造函数,又可以继承原型。3.方便传参。4.可以多继承构造函数。 但是我们为什么没有提到原型链的继承呢,因为原型链继承依旧有参数的隐患,所以暂且不适用。
5.class继承
class Parent{
constructor(s){
this.skill = s;
}
show(){
console.log(this.skill);
}
}
class Child extends Parent{
constructor(n){
super(n);
}
}
var p = new Parent("zhangshan");
p.show();//zhangshan
var c = new Child("lisi");
c.show();//lisi
当我们在ES6的class继承中,我们发现这是一种很便捷的继承方式,主要就是靠的extends和super。但是他的原理就是:构造函数方式继承 + 原型链继承。