js继承

原型链继承

Posted by Jeremy on April 30, 2019

继承

原型链继承

ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原 型让一个引用类型继承另一个引用类型的属性和方法构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型 对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的 原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数 的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实 例与原型的链条。这就是所谓原型链的基本概念。

通过例子深入理解

    function Father() {
         this.fatherage = 45
    }
    Father.prototype.getFatherAge = function () {
        return this.fatherage
    }
    function Son() {
        this.sonage = 20
    }
    Son.prototype.prosonage = 20;                      //在此处添加属性 Son的原型对象上没有此属性 why???
    Son.prototype.getSonAge = function () {            //在此处添加方法 Son的原型对象上没有此方法 why???
        return this.sonage
    }
    Son.prototype = new Father();
    Son.prototype.getSonAge = function () {
        return this.sonage
    }
    var relationship = new Son();
    console.log(relationship);

通过控制台打印构造函数Son的实例对象 relationship 可以看到 relationship对象包含了自身的属性sonage和一个__proto__属性,该属性是一个普通对象,指向的 是构造函数Son的原型对象,上面代码中我们将 Son的原型对象等于Father的实例,所以Son的原型对象中 会包含一个指向Father原型对象的指针,即 Son.prototype.proto === Father.prototype

Father原型对象包含一个指向构造函数(Father)的指针constructor

特别注意

此时 relationship的 cunstructor属性指向的是Father,这是因为 Son的原型指向了另一个对象—— Father 的原型,而这个原型对象的 constructor 属性指向的是 Father。 Son.prototype.constructor === Father //true

所有的函数默认原型都是Object的实例,所以Father的原型对象会包含一个指向Object原型的指针, 即 Father.prototype.proto === Object.prototype,所以所有自定义类型都会继承 toString()、 valueOf()等默认方法 Object.prototype.proto 指向null

这个例子中的实例以及构造函数和原型之间的关系如下图所示

原型搜索机制。读取模式访问一个实例属性时,首先会在实例中搜索该属性。如果没有找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。 就拿上面的例子来说,调用 relationship.getFatherAge()会经历三个搜索步骤:1)搜索实例;2)搜索 Son.prototype; 3)搜索 Father.prototype,最后一步才会找到该方法。 在找不到属性或方法的情况下,搜索过 程总是要一环一环地前行到原型链末端才会停下来。

当创建一个函数的时候,会自动为该函数创建一个prototype属性,这个属性指向函数的原型对象,所有的原型对象都有一个constructor属性,该属性指向函数本身

所以可以这样来理解 ,原型对象的construtor属性指向函数本身,函数本身有个一
prototype属性又会指向函数的原型对象,从控制台中可以看出