zoukankan      html  css  js  c++  java
  • Javascript深入__proto__和prototype的区别和联系

    有一个一个装逼的同事,写了一段代码

    function a(){}
    a.__proto__.__proto__.__proto__

    然后问我,下面这个玩意a.__proto__.__proto__.__proto__是啥,然后我一脸懵逼,prototype还知道一点,这个__proto__,还来三个,是个什么鬼。于是我一直不能放下这个问题,虽然我很懒,很不喜欢费脑子,但是这个坎还是过不去,最近两天研究了大半天,就有了这篇文章。
    我先说出答案, 上面的值为 null。我还很负责的告诉你,下面的_a.__proto__.__proto__.__proto__也是null

    function a(){}
    var _a = new a();
    _a.__proto__.__proto__.__proto__

    先来一张非常经典的图,真的是非常经典,你看懂他,你就懂了整个世界,然后整个世界就等着你去拯救整个世界。
    原型关系图)

    正文之前,__proto__和prototype

    都谁有的问题

    typeof === object的有__proto__ , null和undefined都没有
    typeof === function的有__proto__和prototype

    __proto__ 是什么
    __proto__ 一般情况指向的是该对象的构造函数的prototype,一般情况,因为还有很二般的情况。
    先来看个简单的例子, 下面的输出是true

    function a(){}
    var _a = new a()
    console.log(_a.__proto__ === a.prototype)

    那我问_a.__proto__.__proto__为什么呢,你会这么推导么,
    依据上面_a.__proto__ === a.prototype,那么_a.__proto__.__proto__就等同a.prototype.__proto__ , 那么我们就再推到等于 a.prototype.constructor.prototype,然后你去一比,结果是false。

    _a.__proto__.__proto__  === a.prototype.constructor.prototype  
    // false

    几条规则
    这个先不纠结, 我们先看看上图,我们先得知道或者记住这几个规则

    1. Object.prototype.__proto__ === null
      不要纠结,铁律
    2. Object.__proto__ === Function.prototype
      Object,Number, Error等等这些函数都是Function创建的,下面就说明
      这些的constructor就是Function,这里比较有意思的就是 Function.constructor也是Function。
      那就有Object.__proto__ === Function.prototype === Function.__proto__

      Object.constructor.prototype  === Function.prototype  
      // true
      Function.constructor === Function
      // true
    3. Function.prototype.__proto__ === Object.prototype
      这个就是这样的设计,

      Function.prototype.constructor === Object 
      // false

      进入正题

      有这几个基本东西,我们就可以来推导了。

    先看下面的代码,
    js 我们来推到 aaa.__proto__.__proto__.__proto__

    function aaa(){} 
    var _aaa = new aaa()
    1. aaa.__proto__
      aaa构造函数是Function
      aaa.constructor === Function
      aaa.__proto__ === Function.prototype

    2. aaa.__proto__.__proto__
      aaa.__proto__.__proto__ === Function.prototype.__proto__
      依据 Function.prototype.__proto__ === Object.prototype
      aaa.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype

    3. aaa.__proto__.__proto__.__proto__
      aaa.__proto__.__proto__.__proto__ === Object.prototype.__proto__
      依据 Object.prototype.__proto__ === null
      aaa.__proto__.__proto__.__proto__ === null

    还是上面代码,我们接着推导_aaa.__proto__.__proto__.__proto__

    1. _aaa.__proto__
      _aaa的构造函数是 aaa
      _aaa.constructor === aaa
      _aaa.__proto__ === _aaa.constructor.prototype
      _aaa.__proto__ === aaa.prototype

    2. _aaa.__proto__.__proto__
      _aaa.__proto__.__proto__ === aaa.prototype.__proto__
      参考图,Foo.prototype.__proto__ === Object.prototype
      _aaa.__proto__.__proto__ === aaa.prototype.__proto__ === Object.protype

    3. _aaa.__proto__.__proto__.__proto__
      _aaa.__proto__.__proto__.__proto__ === Object.protype.__proto__
      依据 Object.prototype.__proto__ === null
      _aaa.__proto__.__proto__ === null

    正文延伸, 加上继承关系

    我们再来看看,带继承关系的

    function aaa(){}
    function bbb(){}
    bbb.prototype = new aaa()
    var _bbb = new bbb();

    bbb.__proto__.__proto__.__proto__ === null
    这个没啥好说,
    关键来看看 bbb.prototype.__proto__.__proto__.__proto__

    1. bbb.prototype.__proto__
      bbb.prototype.__proto__ === bbb.prototype.constructor.prototype
      bbb.prototype的原型是 aaa的实例, bbb原型的构造函数就是aaa,所以
      bbb.prototype.__proto__ === aaa.prototype

    2. bbb.prototype.__proto__.__proto__
      bbb.prototype.__proto__.__proto__ === aaa.prototype.__proto__
      参考图,Foo.prototype.__proto__ === Object.prototype
      bbb.prototype.__proto__.__proto__ === Object.prototype

    3. bbb.prototype.__proto__.__proto__
      bbb.prototype.__proto__.__proto__ .__proto__=== Object.prototype.__proto__ === null

    再来看看_bbb.__proto__.__proto__.__proto__ .__proto__

    1. _bbb.__proto__
      _bbb.__proto__ === bbb.prototype
    2. _bbb.proto.proto
      _bbb.__proto__.__proto__ === bbb.prototype._proto__ === bbb.prototype.constructor.prototype === aaa.prototype
    3. _bbb.proto.proto.proto
      _bbb.__proto__.__proto__.__proto__ === aaa.prototype.__proto__
      参考图Foo.prototype.__proto__ === Object.prototype
      _bbb.__proto__.__proto__.__proto__ === aaa.prototype.__proto__ === Object.prototype
    4. _bbb.__proto__.__proto__.__proto__.__proto__
      _bbb.__proto__.__proto__.__proto__.__proto__ === Object.prototype.__proto__ === null

    正文 再加量

    看看如下代码

    function aaa(){}
    var _aaa = new aaa()
    
    function bbb(){}
    bbb.prototype = new aaa();
    
    var _bbb = new bbb();
    
    function ccc(){}
    ccc.prototype = new bbb()
    var _ccc = new ccc()

    我们再来分析_ccc的prototype__proto__,你们会说,你有完没完
    ,那我就不分析了,我来推断:

    推断:

    1. 任何自定义的function本身,三次__proto__必然是null,也就是往上找三代
      包括Function,Object, Error等等
      Fucntion.proto 看图,依据
      Object.__proto__ === Function.prototype === Function.__proto__
      我们来推导Function.__proto__.__proto__ .__proto__
      第一步:Function.__proto__ === Function.prototype
      第二步:Function.__proto__.__proto__ === Function.prototype.__proto__ === Object.protetype
      第三步:Function.__proto__.__proto__ .__proto__ === Object.protetype.__proto__ === null
      都是Function构造出来的
      我们来测试一下ccc

      ccc.__proto__.__proto__.__proto__ === null // true
    2. 继承关系的function fn,假设继承次数为n,
      _fn = new fn();
      那么 _fn.__protot__[3 + n] === null
      _ccc应该是3+2就是5次

      _ccc.__proto__.__proto__.__proto__.__proto__.__proto__ === null // true
    3. 继承关系的function fn,假设继承次数为n
      推到 fn.prototype.__proto__[3+n-1]
      ccc应该是 4次__proto__

      ccc.prototype.__proto__.__proto__.__proto__.__proto__ === null // true

      当然上面关联的关系,就自己慢慢看吧

    正文之外, class

    下面的代码也是遵守规则,至于为什么,问自己喽。

    class aaa {}
    class bbb extends aaa{}
    class ccc extends bbb{};
    var _ccc = new ccc()

    关于Number,Boolen, String,Function, Date, Array, RegExp等的__proto__prototype.proto`

    1. __proto__
      因为这些都是Function创建出来的函数,__proto__在函数上时就是表示构造函数的prototype,所以
      .__proto__ === .constrcutor.prototype === Function.prototype
    2. .prototype.__proto__ 这些老骨头不遵循 __proto__ 为构造函数的prototype
      在上面提到过了,Function.prototype.__proto__ === Object.prototype
      类推,这些内置的老骨头的 .prototype.__proto__ === Object.prototype

    ## 总结
    总结, 特别需要记忆的:

    1. Object.prototype.__proto__ === null
    2. Function.prototype.__proto__ === Object.prototype
      内置Number,Boolen, String,Function, Date, Array, RegExp等一样
    3. Object.__proto__ === Function.prototype === Function.__proto__
      联系2,这些东西都是Function创建出来的
    4. Math, JSON的__ptoto__是 Object.prototype
      typeof 可以看出来这两个是object,而不是Function
    5. function a(){} 这样创建出来,没有继承关系的函数
      a.prototype.__proto__ === Object.prototype
    6. 有继承关系的function看上面的推断
    7. 对象字面量和new Object() 比如, var a ={}, b = new Object(), c = [];
      a.__proto__ === a.constructor.prototype === Object.protype
      a.__proto__.__proto__ === Object.protype.__proto__ === null
    8. 基本数据类型string,number,boolean,比如 var a = '', b=10, c= false,
      b.__proto__ === b.constructor.prototype === Number.prototype
      b.__proto__.__proto__ === Number.prototype.__proto__ === Object.prototype
      b.__proto__.__proto__.__proto__ === Object.prototype.__proto__ === null
    9. null和undefined没有__proto__

    最终

      1. 看图
      2. 浏览器输入 xx.__proto__ 或者xx.prototype自己看去
  • 相关阅读:
    eslint 的 env 配置是干嘛使的?
    cookie httpOnly 打勾
    如何定制 antd 的样式(theme)
    剑指 Offer 66. 构建乘积数组
    剑指 Offer 65. 不用加减乘除做加法
    剑指 Offer 62. 圆圈中最后剩下的数字
    剑指 Offer 61. 扑克牌中的顺子
    剑指 Offer 59
    剑指 Offer 58
    剑指 Offer 58
  • 原文地址:https://www.cnblogs.com/ghyes/p/9153342.html
Copyright © 2011-2022 走看看