关于原型和原型链的详细理解

作者: 我住隔壁我姓吴 | 来源:发表于2016-12-28 10:05 被阅读640次

    在浏览本文之前首先明白什么是对象?,在JavaScript中我们会用typeof( )这个函数,那么使用typeof( )输出的值一般会有number、boolean、string、undefined、function、object等这些类型,那我们本文要研究的就是object和function这两种类型,返回值是这两种类型的就是我们本文所要研究的对象

    什么是对象?

    那么对象该如何去定义呢?我个人认为对象就是一些属性的集合。举个栗子🌰

     var Laowang={
         'name':'老王',
         'feature':'热心肠',
         'skill':function( ){
              alert('特长是修水管');
     }
    }
    

    那么在上面的例子中'Laowang'就是一个对象,你肯定会有疑问关于我对对象的定义,在'Laowang'这个对象中出现了function方法,但是这个方法在'Laowang'这个对象中是以键值对的形式出现的,所以这个function就是'skill'这个属性的属性值。所以验证了对象就是一些属性的集合这句话。

    上面的例子很好理解,但是数组和函数好像不能这样去定义属性,但他们也是对象啊,不要迷惑,他们有自己定义属性的方法。以函数为例:

    var laowang=function( ){
          alert('修水管');
    }
    laowang.skill='热心肠';
    laowang.skill2='爱串门';
    laowang.skill3={
        'a':'亲切问候邻居家孩子'
    }
    

    这不,function就被赋予了skill、skill2、skill3这三个属性。

    上面说到function和objec这两个返回值是对象,既然都是对象,为什么返回的不是一个值。由于function和object的关系比较特殊所以返回的值不同,我在下文会详细讲到function和object的'特殊关系'

    function和object的关系

    上文说道function和object都是对象,但是function的返回值是function而不是object,那么他俩之间肯定有某种'神秘的关系'。

    function和object的关系其实就像'先有蛋还是先有鸡'这种让你抓狂的问题。function是object的一种,但是object又是由function创建的,什么,你要打我脸?

    var arr=['a','b','c'];
    var obj={
        'name':'老王',
        'age':'99'
    }
    

    以上两个都是对象,但是都不是由function创建的,不要忘记了这种写法只是用字面量的方式来创建对象的。这种写法只是为了让代码更简单明了更容易理解。归根到底以上两种对象是由function创建的,请看以下代码:

    var arr=new Arry('a','b','c');
    var obj=new Object();
    obj.name='老王';
    obj.age='99';
    

    在以上代码中Arry( )和Object( )都是函数,通常我们把他们当做构造函数,由构造函数我们可以new出很多实例对象,构造函数和我们平常自定义的函数没有语法上的区别,区分就是构造函数一般首字母是大写的。

    是不是感觉很乱?为什么function和object的关系是这样的,不要慌张,耐心看完本文你就会豁然开朗。

    原型(prototype)

    上面扯了半天对象,到这里终于讲到本文的主要内容了--原型(prototype)。

    那么prototype到底是什么呢?不要着急,让我们一步步来。

    上面我们说到function也是一种对象,现在对这个应该没有任何疑问了,如果有疑问请滑动你的鼠标从头开始看!!

    function作为对象,那么他肯定是若干属性的集合,在JavaScript中,function默认有一个属性,这个属性就是prototype,既然是属性那么肯定有相对应的属性值,prototype的属性值是一个对象,既然是对象,那么肯定是若干属性的集合,这个对象里有一个默认的属性:constructor,这个属性相当于一个'指针',指向这个函数本身。
    以下图为例:


    上图的o1和o2是由Object实例化出来的,他们的_ proto_指向的是Object.prototype,这就说明:每个对象都有一个_ proto_属性,指向创建该对象的构造函数的prototype

    那么你肯定会问'每个对象都有一个_ proto_属性,指向创建该对象的构造函数的prototype',那Object也是一个对象,肯定也有_ proto_属性,那他指向谁?

    关于Object._ proto_的指向问题很特殊,在这个Object._ proto_是个特例,它指向null,这个地方大家一定要牢记。

    也许你还会有另一个疑问,函数也是对象,实例化出来的函数的_ proto_属性指向其构造函数,那么其构造函数的_ proto_指向谁?

    Function这个前面没有提到,现在拿出来晒晒,构造函数是由谁创建的,就是由Function这个函数创建的,所以你上面的疑问就很好解答了。再用一张图让你更清晰的看清他们的关系:



    这张图清晰的表明了自定义构造函数、Object、Function之间的关系!

    眼神好的人会在上图发现一个问题:自定义函数Foo._ proto_指向Function.prototype,Object._ proto_指向Function.prototype,怎么Function._ proto_也指向Function.prototype,这不就是形成了一个'死循环'么,来,让我们仔细捋一捋,Function也是一个函数,既然是函数那么他肯定是由Function创建的,那么上面的'死循环'就解释通了。

    在这里我还要解释一个地方,Function.prototype也是一个对象,那其肯定有_ proto_属性,那么指向谁呢?其指向Object.prototype,为什么呢?Function.prototype是一个普通的对象,就可以看成这个对象是由Object实例化出来的,那么Function.prototype._ proto_指向就是Object.prototype了。

    下面上一张完整的图片,大家可以按照下面这种图片捋一下自己的思路,因为上面讲了那么多肯定会有些乱。



    这张图完整的呈现出了实例对象、自定义函数、Object、Function之间种种错综复杂的关系,不要怕麻烦,一条一条的去找对应的关系。

    继承

    为什么会说到继承呢,因为继承是通过原型链来体现的,所以一并放在这里讲了。我们先看一段代码:

    function Person(){  }
      var p1=new Person();
      Person.prototype.name='老王';
      Person.prototype.age='99';
      console.log(p1.name);//'老王'
    

    以上代码中,p1是Person实例化出来的函数,我并没有给p1定义name这个属性,那p1.name是怎么来的--是从Person.prototype来的,因为p1._ proto_指向Person.prototype当访问对象的某个属性时,现在这个对象本身去找,如果找不到那就顺着_ proto_往上找,直到找到或者Object.prototype为止

    由于所有的对象的原型链都会找到Object.prototype,因此所有的对象都会有Object.prototype的方法。这就是所谓的“继承”。

    讲到这里,关于原型和原型链就结束了,希望各位能深刻的理解。

    相关文章

      网友评论

      • cbd16aeb86b3:大神,我想找些ajax的实战项目练练手,有介绍吗?😀
        我住隔壁我姓吴:@小菜鸟2017 瀑布流
      • cbd16aeb86b3:p1._ proto_指向Person.prototype,意思是什么?_?是p1._ proto_===erson.prototype吗?😀
        我住隔壁我姓吴:@小菜鸟2017 是原型对象里有一个默认的constructor属性,这个属性没什么太大用处,你只需要记住他指向谁就好了。
        cbd16aeb86b3:对象里有一个默认的属性:constructor,这个属性相当于一个'指针',指向这个函数本身,这又是什么意思?
        我住隔壁我姓吴:@小菜鸟2017 是这样的

      本文标题:关于原型和原型链的详细理解

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