什么是继承?
继承就是让一个没有某个属性或方法的对象能够使用另一个具有某个方法或属性的对象的属性或方法。
例如:
var obj = {
name:"obj",
show:function(){
console.log(this.name);
}
}
var obj2 = {
name:"obj2"
}
那么如何利用show,打印出obj2的名字?
obj.show(); // obj
obj.show.call(obj2);
obj2.show();// obj2
这里我们通过call改变this指向,所以obj2可以执行obj2的show方法。 以上是实例和实例之间的继承,但是规模太小。这里我们要做的是构造函数和构造函数之间的继承。那么继承有什么方法?本章主要介绍以下4中方法:
原型的继承
构造函数的继承
混合继承(组合)
ES6 class 继承
- 原型的继承
首先我们先写两个方法
function Parent(){
}
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(){
}
然后我们通过child的原型找到parent的原型
Child.prototype = Parent.prototype;
执行结果:
var p = new Parent();
p.show();//哈哈哈
var c = new Child();
c.show();//哈哈哈
但是在这里有一个问题,如果我们通过child的原型创造一个跟parent一样的show方法,会覆盖parent的show方法
Child.prototype.show = function(){
console.log("hello");
}
p.show();//hello
c.show();//hello
为什么呢?因为这里是浅拷贝,prototype是一个对象,简单的赋值就是浅拷贝,改变其中一个,就会影响到另一个。所以我们这要深拷贝
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
这样我们改变child的方法,就不会影响到parent了。
p.show();//哈哈哈
c.show();//hello
我们这里成这种方法为原型对象继承,特点就是简单,方便,易操作。但是,只能继承原型身上的方法和属性,不能继承构造函数内的方法和属性。如下
function Parent(){
this.name = "parent";
}
console.log(p.name);//parent
console.log(c.name);//undefined
怎么解决这种情况呢?我们继续分析。同样先创建两个函数
function Parent(){
this.name = "admin";
}
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(){
}
因为我们这里还是原型继承,那么我们继续找child的原型,然后我们让child的原型等于另一个构造函数的的实例。
Child.prototype = new Parent();
执行结果
var p = new Parent();
p.show();//哈哈哈
console.log(p.name);//admin
var c = new Child();
c.show();//哈哈哈
console.log(c.name);//admin
我们就可以得到parent的身上和构造函数的方法和属性。而且这里改写child的show方法和属性也不会改变parent的方法和属性。
我们称这种方法为原型链继承,特点:
1.更加的简单,方便,易操作
2.不仅可以继承原型身上的方法和属性,而且还可以继承构造函数中的方法和属性
3.但是,不方便传参
什么意思呢?看代码
function Parent(n){
this.name = n;
}
Parent.prototype.show = function(){
console.log(this.name);
}
function Child(n){
}
Child.prototype = new Parent();
//执行结果
var p = new Parent("张三");
p.show();//张三
var c = new Child();
c.show();//undefined
如果需要解决传参的话,我们需要给parent的实例传
Child.prototype = new Parent("李四");
这样就解决的传参,但是看上起很奇怪,不方便。
- 构造函数的继承
function Parent(s){
this.skill = s;
}
function Child(n){
Parent.call(this,n)();
}
执行结果
var p = new Parent("大");
console.log(p.skill);//大
var c = new Child("小");
console.log(c.skill);//小
这里利用this的改变实现,在Child中执行Parent的同时,修改this指向,为Child的this,因为Child将来被new执行,Child中的this,指向将来Child的实例。注意,call可以改成bind或apply,但是要注意他们本身的使用方法。
构造函数继承说白了就是改变this指向继承,特点:
1.方便的传参
2.还可以实现多继承
3.但是,只能继承构造函数内部的属性或方法,不能继承原型身上的属性或方法
Parent.prototype.show = function(){
console.log(this.skill);
}
//执行
p.show();//大
c.show();//这里会报错
上面我们说构造函数继承可以多继承,那么什么是多继承,如下
function Mp3(){
this.music = "放音乐";
}
function Camera(){
this.photo = "拍照";
}
function Tel(){
this.call = "打电话";
}
function Email(){
this.message = "发信息";
}
function MobilePhone(n){
Mp3.call(this);
Camera.call(this);
Tel.call(this);
Email.call(this);
this.name = n;
this.game = "打游戏";
}
var mp = new MobilePhone("HUAWEI P30");
console.log(mp);//MobilePhone {music: "放音乐", photo: "拍照", call: "打电话", message: "发信息", name: "HUAWEI P30", …}
- 混合继承
混合继承其实将原型继承和构造函数继承组合起来
function Parent(s){
this.skill = s;
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(s){
Parent.call(this, s);
}
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
console.log("hello");
}
var p = new Parent("大");
p.show();//大
var c = new Child("小");
console.log(c.skill);//小
c.show();//hello
混合继承的特点:
1.略复杂
2.既可以继承构造函数,又可以继承原型
3.方便传参
4.可以多继承构造函数
5.注意:原型链继承时,依然有参数隐患
- ES6 class 继承
ES6语法中,提供了非常简单的继承方法
class Parent{
constructor(s){
this.skill = s;
}
show(){
console.log(this.skill);
}
}
class Child extends Parent{
constructor(s){
super(s);
}
}
var p = new Parent("大");
p.show();//大
var c = new Child("小");
c.show();//小
ES6的class继承,原理就是:构造函数方式继承 + 原型链继承,不过ES6帮忙我们封装好了。
以上就是我要介绍的继承方法,不足之处请指出。