美文网首页编程
浅谈JavaScript原型链和寄生式继承的实现

浅谈JavaScript原型链和寄生式继承的实现

作者: Null丶sleep | 来源:发表于2020-09-22 10:59 被阅读0次

    JavaScript原型链的问题在面试经常遇到 , 有时候我们很难搞懂其中的关系 ! 今天我们来谈谈 JavaScript 中 原型链的问题!

    1. 什么是原型?
      函数原型:
      在JavaScript中,函数不仅仅是一个可以重用的代码块,而且还可以作为一种数据使用。在堆空间中为函数分配了它的存储空间,函数名或函数的其他形式的引用保存了这个存储空间的引用地址。所以JavaScript中的函数是一种引用数据类型,这就是为什么我们说JavaScript中的函数也是对象。
      那么函数这样的对象有很多特殊的性质,原型就是其中之一。每一个函数对象都包含一个属性:prototype。当我们声明一个函数时,函数对象就创建好了。而函数对象创建的同时,系统还会同时创建一个对象,并让函数对象的prototype属性指向它。
      比如说,当我们执行下面代码时:
      function Person ( perName,perAge ) { //… }
      就声明了一个函数,系统会将这个函数对象创建出来。内存中应该是这样的情况:


      image.png

    但是更深层次挖掘一下,我还需要知道创建函数对象的同时,还会创建一个“原型对象”,由函数对象的prototype属性指向这个原型对象

    image.png
    对象原型:
    函数可以和以它为构造器所创建的所有对象共享原型对象。就比如本文最初展示的代码中,per01和per02都是Person函数创建的,那么per01或per02就可以通过自身的proto属性关联到Person对象的原型。
    下图表示了它们之间的关系
    image.png
    所以函数的原型对象是可以为所有被创建对象共享的,我们就可以将我们要为所有对象都添加的属性添加到原型对象上, 从而实现寄生式继承
    function Person(perName,perAge,gender){
    this.perName = perName;
    this.perAge = perAge;
    this.toString = function(){
    return “PersonName=”+this.perName+” PersonAge=”+this.perAge;
    };
    }
    var per01 = new Person(“Bob”, 20);
    var per02 = new Person(“Kate”, 25);
    Person.prototype.message = “Atguig is very good”;
    console.log(per01.toString()+” message=”+per01.message);
    console.log(per02.toString()+” message=”+per02.message);
    //执行结果:
    //PersonName=Bob PersonAge=20 message=Atguig is very good
    //PersonName=Kate PersonAge=25 message=Atguig is very good
    

    JavaScript引擎在读取per01对象的message属性时先在当前对象本身的空间内查找,如果能找到则直接返回,如果找不到则沿着proto属性找到原型对象,再在原型对象中查找message属性。

    1. 什么是原型链
      在研究了对象原型和函数原型的关系后,我们还可以进一步深入思考:既然原型对象是一个“对象”,那么这个对象有没有proto这个属性呢?当然有!
    function Person(perName,perAge,gender){
    this.perName = perName;
    this.perAge = perAge;
    this.toString = function(){
    return “PersonName=”+this.perName+” PersonAge=”+this.perAge;
    };
    }
    var person = new Person(“Tom”, 20, “male”);
    console.log(person.__proto__);
    console.log(person.__proto__.__proto__);
    //执行结果:
    //Person {}
    //Object {}
    

    说明person.proto所指向的对象是由Person函数创建的,而person.proto.proto所指向的对象是由Object函数创建的。
    就对象的本质而言,任何一个对象都是以new 构造器函数的方式创建的,所以所有对象都和构造器函数共享原型对象。这样说可能你会有疑问,我可以通过{属性名:属性值}的方式创建对象呀,这里并没有用到构造器函数呀?那么情看下面的代码:

    var obj = {“myName”:”Jerry”,”myAge”:15};
    console.log(obj.constructor);
    console.log(obj.__proto__ === Object.prototype);
    //执行结果:
    //function Object()
    //true
    

    说明从本质上来说,任何对象的创建都依赖对应的构造器函数,当然也包含原型机制。既然如此,那么原型对象本身也是一个对象,这个对象也指向一个原型对象,那么原型对象的原型对象也是对象,可以继续指向一个原型对象……这就是原型链。


    image.png

    但原型链并不是无止境的,到Object()函数为止。

    var obj = {“myName”:”Jerry”,”myAge”:15};
    console.log(obj.__proto__.__proto__);
    //执行结果:
    //null
    
    1. 如何快速理解原型链
      其实原型链理解起来不难, 我这里整理的一张图 , 大家可以看看 仅供参考 !

    相关文章

      网友评论

        本文标题:浅谈JavaScript原型链和寄生式继承的实现

        本文链接:https://www.haomeiwen.com/subject/wclbyktx.html