红宝书之—JavaScript如何是实现继承?

时间:2021-2-20 作者:admin

JavaScript实现继承

很多面向对象的语言都支持两种继承:接口继承和实现继承。前者只继承签名,后者继承实际的方法。但是接口继承在ECMAScript中是不可能的,因为函数没有签名。实现继承是ECMAScript唯一支持的继承方式,而这主要是通过==原型链==实现的

什么是原型链?

ECMA-262把原型链定义为ECMAScript的主要继承方式,其基本思想就是通过原型继承多个引用类型的属性和方法。

在此之前需要掌握构造函数、原型和实例之间的关系:

每个构造函数都有一个原型对象,原型有一个属性指回这个构造函数,而实例有一个内部指针指向原型。如果这个原型是另一个原型的实例呢?那就意味着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。

这样就在实例和原型之间形成了一个原型链。

这就是原型链的基本构想。

实现简单原型链:

下面是一个简单原型链的实现代码:

function SuperType(){
    this.prototype = true
}

SuperType.prototype.getSuperValue = function(){
    return this.prototype
}

function SubType(){
    this.subProperty = false
}

//继承 superType
SubType.prototype = new SuperType()

SubType.prototype.getSubVaule = function(){
    return this.subProperty
}

let instance = new subType()

console.log(instance.getSubVaule()) //false
console.log(instance.getSuperValue())    //true    

以上代码定义了两个类型SuperTypeSubType,这两个类型分别定义了一个属性和一个方法,然后SubType通过创建SuperType的实例并将其赋值给自己的prototype,实现了对SuperType的继承。

这个赋值重写了SubType最初的原型,将其替换成了SuperType的实例。这意味着SuperType实例可以访问的所以属性和方法也会存在于SubType的原型上。这样实现了继承之后,又给SubType的原型也就是SuperType的实例添加了一个新方法。

最后又创建了SubType的实例instance,并成功调用了它继承的getSubVaule()和getSuperValue()方法。

上面代码中实现继承的关键,是SubType没有使用默认原型,而是将其替换成了一个新的对象,这个对象就是SuperType的实例。这样,SubType的实例不仅能从SuperType的实例中继承属性和方法,而且还与SuperType的原型挂上了钩。

于是instance(通过内部的[[Prototype]])指向SubType.prototype,而SubType.prototype(作为SuperType的实例又通过内部的[[Prototype]])指向SuperType.prototype.

注意,由于SubType.prototype的constructor属性被重写为指向SuperType,所以instance.constructor也指向SuperType。

扩展补充:

原型链是原型搜索机制的扩展运用,我们都知道,在读取实例上的属性时:

  1. 首先会在实例上搜索这个属性
  2. 如果没有找到,则会继承搜索实例的原型

在通过原型链实现继承后,搜索就可以继承向上,搜索原型的原型。

对于前面的例子,instance.getSuperValue()经历了3个搜索步骤:

  1. instance
  2. SubType.prototype
  3. SuperType.prototype

在最后一步才找到这个方法。

对属性和方法的搜索会一直持续到原型链的顶端

参考文献

JavaScript高级程序设计—继承

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。