欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JS的几种继承方式介绍

程序员文章站 2022-03-28 19:16:20
原型链继承 当我们每创建一个函数时,该函数都会自带一个prototype属性,该属性会指向另一个对象,指向的这个对象就是该函数的原型对象。原型对象中又有一个指向构造函数的属性。通过new 构造函数的...

原型链继承

当我们每创建一个函数时,该函数都会自带一个prototype属性,该属性会指向另一个对象,指向的这个对象就是该函数的原型对象。原型对象中又有一个指向构造函数的属性。通过new 构造函数的实例会指向原型对象。通过该特性,可以通过原型链实现继承。

1   //定义父类
2   function parent(){
3       this.property='超类';
4   }
5   parent.prototype.constructor=parent;
6   parent.prototype.getvalue=function(){
7       return this.property;
8   }
9   //定义子类
10  function son(){
11      this.property=false;
12  }
13  //通过原型继承parent
14  son.prototype=new parent();
15  son.prototype.constructor=son;
16  //在子类重写父类方法或添加新方法时,重写的方法和新添加方法的代码需要放在继承语句之后。
17  //重写父类的方法
18  son.prototype.getvalue=function(){
19      console.log('重写的getvalue方法');
20  }
21  //新添加的方法
22  son.prototype.showmsg=function(){
23      console.log('新添加的方法');
24  }
25  var s=new son();
26  s.getvalue();   //重写的getvalue方法
27  s.showmsg();    //新添加的方法

需要注意的一点是,在通过原型链继承时,不能使用对象字面量的方式给原型对象方法,因为这样会重写掉原型链(对象字面量都是object的实例)。

1       function parent(){
2           this.attr='test attr';
3       }
4       function son(){}
5       //原型链继承parent
6       son.prototype=new parent();
7           //通过对象字面量给原型添加方法
8       son.prototype={
8           showattr=function(){
10              console.log(this.attr);
11          }
12      };
13
14      var s=new son();
15      s.showattr();   //报错
原型链的问题

当通过原型链进行继承时,原来父类型的引用类型的属性会变成子类型原型对象的实例。即该属性会被子类型实例的公共属性。

1   function super(){
2       this.colors=['blue','red'];
3   }
4
5   function sub(){}
6   sub.prototype=new super();
7   var sub1=new sub();
8   sub1.colors.push('green');
9   console.log(sub1.colors);  //["blue", "red", "green"]
10  var sub2=new sub();
11  console.log(sub2.colors);  //["blue", "red", "green"]

构造函数继承

构造函数继承可以解决原型链继承的问题。

在子类型构造函数中使用call和apply方法调用父类型的构造方法实现继承

1   function super(name,age){
2       this.friends=['kkk','abc'];
3       this.name=name;
4       this.age=age;
5   }
6
7   function sub(){
8       //super.call(this);
9       super.apply(this,arguments);
10  }
11  var s=new sub('aaa',22);
12  s.friends.push('new');
13  console.log(s.friends);  //["kkk", "abc", "new"]
14  console.log(s.name);  //aaa
15  console.log(s.age);   //22
16
17  var s1=new sub();
18  console.log(s1.friends);  // ["kkk", "abc"]

由s.friends和s1.friends返回的结果可知,原型链继承的问题可以由构造方法继承方法解决,但这种继承方法也存在问题:

构造函数继承的问题

由于所有的属性和方法都在构造函数上,每创建一个实例,相同功能的方法却同时占不同的内存,造成内存浪费。

组合继承

组合继承、即由原型链继承和构造函数继承组合在一起实现继承。该继承方式简单来说就是使用原型链继承原型的方法、通过构造函数继承方式继承属性。

1   //组合继承
2   function super(name,age){
3       this.name=name;
4       this.age=age;
5       this.friends=['aaa','bbb'];
6   }
7   super.prototype={
8       constructor:super,
9       getmsg:function(){
10          console.log(this.name+' '+this.age)
11      }
12  }
13  
14  function sub(name,age,hobby){
15      //属性通过构造方法继承
16      //super.call(this,name,age);
17      super.apply(this,[name,age]);
18
19      //补充:为了避免父类的属性重写子类新增的属性或重写子类的属性,应将继承语句放在子类的第一行。
20      this.hobby=hobby;
21  }
22  //通过原型链继承方法。
23  sub.prototype=new super();
24  sub.prototype.constructor=sub;
25  sub.prototype.getsubmsg=function(){
26      console.log(this.name+' '+this.age+' '+this.hobby+' '+this.friends);
27  }
28  var s=new sub('kevin',22,'篮球');
29  s.friends.push('ccc');
30  s.getmsg(); //kevin 22
31  s.getsubmsg();  //kevin 22 篮球 aaa,bbb,ccc
32  
33  var s1=new sub('paul',28,'电影');
34  s1.getmsg();    //paul 28
35  s1.getsubmsg(); //paul 28 电影 aaa,bbb

由代码结果可知,组合继承方式融合了原型链继承和构造方法继承的优点,又同时避开了它们的缺点。