javascript构造函数的继承简单介绍

快乐打工仔 分类:实例代码

实现继承的方式有多种,下面介绍一下比较常见的几种方式,需要的朋友可以做一下参考。

准备工作:

下面是一个父类,当前ES版本中还没有类这个概念(ES6新增class),不过确实是类的作用:

function Web(){
  this.target="用户浏览";
}

下面是一个子类:

function Antzone(webName,url){
  this.webName=webName;
  this.url=url;
}

那面就介绍一下如何让子类来继承父类中的相关属性。

一.构造函数绑定:

使用call()或者apply()方法可以实现此功能。

所谓的构造函数绑定,就是将父类构造函数绑定到子类对象上,代码实例如下:

function Web(){
  this.target="用户浏览";
}
 
function Antzone(webName,url){
  Web.apply(this,arguments);
  this.webName=webName;
  this.url=url
}
 
var oantzone=new Antzone("前端教程网","pipipi.net");
console.log(oantzone.target);

二.使用prototype原型实现继承:

如果子类Antzone的原型指向父类的对象实例,那么子类的对象实例将会继承父类的所有属性和方法。

代码实例如下:

function Web(){
  this.target="用户浏览";
}
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
Antzone.prototype=new Web();
var oantzone=new Antzone("前端教程网","pipipi.net");
console.log(oantzone.target);

上面的代码实现了继承功能,但是这并不完美,甚至可以说是有问题的。

Antzone.prototype=new Web()是覆盖了子类的原型对象,那么这个时候Antzone.prototype.constructor指向就不是Antzone,而是Web,那么对象实例antzone的constructor就不会指向Antzone了,这样就会导致继承链的紊乱,代码修改如下:

function Web(){
  this.target="用户浏览";
}
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
 
Antzone.prototype=new Web();
Antzone.prototype.constructor=Antzone;
var oantzone=new Antzone("前端教程网","pipipi.net");
console.log(oantzone.target);
console.log(oantzone.constructor==Antzone);

上面的代码重新修改了一下Antzone.prototype.constructor的指向即可。

三.直接继承prototype:

上面代码是继承的父类的对象实例,我们也可以直接继承父类的原型对象,这样的话能够节省内存空间提高效率。

父类中不变的属性可以写在在prototype原型对象中,代码修改如下:

function Web(){
}
Web.prototype.target="用户浏览";
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
 
Antzone.prototype=Web.prototype
Antzone.prototype.constructor=Antzone;
var oantzone=new Antzone("前端教程网","pipipi.net");
console.log(oantzone.target);

这种方式虽然效率比较高,但是也有一个比较严重的问题,那就是一旦修改子类原型对象,那么父类的原型对象也会被修改,因为实质上它俩是指向的同一个原型对象,代码演示如下:

function Web(){
}
Web.prototype.target="用户浏览";
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
 
Antzone.prototype=Web.prototype
Antzone.prototype.constructor=Antzone;
Antzone.prototype.target="div教程";
console.log(Antzone.prototype.target);
console.log(Web.prototype.target);

四.使用空对象进行过渡:

对于上面方式的缺点,下面就进行一下改进,使用一个空对象进行一下过渡。

代码实例如下:

function Web(){
}
Web.prototype.target="用户浏览";
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
var F=function(){};
F.prototype=Web.prototype;
Antzone.prototype=new F();
Antzone.prototype.constructor=Antzone;
var oantzone=new Antzone("前端教程网","pipipi.net");
console.log(oantzone.target);

声明了一个空函数F(),是为了让它足够的"干净",也几乎不占任何内存空间。

修改Antzone的原型的时候也不会影响到父类Web的原型。

代码封装如下:

function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
 Child.prototype = new F();
 Child.prototype.constructor = Child;
 Child.uber = Parent.prototype;
}

extend函数,就是YUI库如何实现继承的方法。

可能其他代码大家都比较明白了,唯独对最后一行代码可能还有点疑问:

Child.uber = Parent.prototype;

为子对象设一个uber属性,这个属性直接指向父对象的prototype属性。

(uber是一个德语词,意思是"向上"、"上一层"。)这等于在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。

一线大厂高级前端编写,前端初中阶面试题,帮助初学者应聘,需要联系微信:javadudu

回复

我来回复
  • 暂无回复内容