6.3继承

    xiaoxiao2022-07-12  143

    继承是oo语言中一个概念。许多oo语言都支持两种继承方式:接口继承和实现继承。ECMAScript只支持实现继承,而且其实现继承主要依靠原型链来实现的。

    6.3.1原型链

    原型链是实现继承的主要方法。基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

    构造函数、原型和实例的关系:

    每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

    原型链的基本概念:

    假如让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,如此层层递进,就构成了实例与原型的链条。

    实现原型链的基本模式:

    function Top() {   this.property = true; } Top.prototype.getTop = function(){     return this.property; } function Bot(){    this.botproperty = false; } Bot.prototype = new Top(); Bot.prototype.getBot= function(){    return this.botproperty; } var instance = new Bot(); console.log( instance.getTop())     // true

    解释:以上代码定义了两个类型:Top  和  Bot。每个类型有一个属性和方法。他们的主要区别是Bot继承了Top,

    而继承是通过创建Top的实例,并将该实例赋给Bot.prototype实现的。实现的本质是重写原型对象,代之以一个新类型的实例。换句话说,原来存在于Top的实例中的属性和方法,现在也存在于Bot。prototype中了。在确立了继承关系之后,我们给Bot。prototype添加了一个方法,这样就继承了Top的属性和方法的基础上又添加了一个新方法。

    调用instance.getTop()  会经历三个搜索步骤  1)搜索实例   2)搜索Bot.prototype   3) 搜索 Top.prototype。

    搜索过程总是要一环一环地前行。

    1.别忘记默认的原型

    所有的引用类型默认都继承了Object,而这个继承也是通过原型链实现的。所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString() 、valueOf()  等默认方法的原因。

    一句话,Bot继承了Top,而Top继承了Object。当调用instance.toString()时,实际上调用的是保存在Object.prototype中的那个方法。

    2.确定原型和实例的关系

    可以通过两种方式来确定原型和实例之间的关系。第一种方式是使用instanceof操作符,测试实例与原型链中出现过的构造函数,结果就会返回true。

    alert( instance instanceof Object )    // true

    alter( instance instanceof Top )   // true

    alter( instance instanceof Bot )   // true

    解释:instance 是 Object、SuperType或SubType中任何一个的实例。

    第二种方法是使用isPrototypeOf() 方法,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型。

    栗子:

    alert( Object.prototype.isPrototypeOf( instance ) )  //true

    alert( Top.prototype.isPrototypeOf( instance ) )  //true

    alert( Bot.prototype.isPrototypeOf( instance ) )  //true

    6.3.2借用构造函数

    function Sup(){    this.colors = ["red","blue","green"] } function Sub () {    Sup.call(this) } var ind = new Sub (); ind.colors.push("black"); console.log(ind.colors)    // ["red", "blue", "green", "black"]

    解释:使用call()或apply()  方法在新创建的Sub实例的环境下调用了Sup构造函数。这样就会在新Sub对象上执行Sup函数中定义的所有对象初始化代码。结果 Sub的每个实例都会具有自己的colors属性的副本了。

    借用构造函数的问题:

    与构造函数模式存在同样都问题-----方法都在构造函数中定义,因此函数复用就无从谈起了。

    最新回复(0)