一文教你深入浅出__proto__和prototype的区别和联系
前话
有一个很喜欢装逼的同事,写了一段代码
1. `function a(){}`
2. `a.__proto__.__proto__.__proto__`
然后问我,下面这个玩意a.proto.proto.proto是啥,然后我一脸懵逼,prototype还知道一点,这个proto,还来三个,是个什么鬼。于是我一直不能放下这个问题,虽然我很懒,很不喜欢费脑子,但是这个坎还是过不去,最近两天研究了大半天,就有了这篇文章。
我先说出答案, 上面的值为 null。我还很负责的告诉你,下面的_a.proto.proto.proto也是null
1. `function a(){}var _a = new a();`2. `_a.__proto__.__proto__.__proto__`
先来一张非常经典的图,真的是非常经典,你看懂他,你就懂了整个世界,然后整个世界就等着你去拯救整个世界。)

正文之前, proto_和prototype
都谁有的问题
typeof === object的有proto , null和undefined都没有 typeof === function的有proto和prototype
proto 是什么?
proto 一般情况指向的是该对象的构造函数的prototype,一般情况,因为还有很二般的情况。先来看个简单的例子, 下面的输出是true
1. `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
几条规则
这个先不纠结, 我们先看看上图,我们先得知道或者记住这几个规则
一.Object.prototype.proto === null
不要纠结,铁律
二.Object.proto === Function.prototype
Object,Number, Error等等这些函数都是Function创建的,下面就说明 这些的constructor就是Function,这里比较有意思的就是 Function.constructor也是Function。那就有Object.proto === Function.prototype === Function.protoObject.constructor.prototype === Function.prototype // trueFunction.constructor === Function// true
Function.prototype.proto === Object.prototype 这个就是这样的设计, Function.prototype.constructor === Object // false
自定义函数,没有修改默认原型的情况下,比如 function Person(){}, Person.prototype.proto === Object.prototype Person.constructor === Function 对比3一看,Function和构造函数是Function的Person,他们prototype.proto的指向是一样的。
进入正题
有这几个基本东西,我们就可以来推导了。
先看下面的代码,
1. `js 我们来推到 aaa.__proto__.__proto__.__proto__`2. `function aaa(){} var _aaa = new aaa()`
1. `aaa.__proto__`2. `aaa构造函数是Function`3. `aaa.constructor === Function`4. `aaa.__proto__ === Function.prototype`
1. `aaa.__proto__.__proto__`2. `aaa.__proto__.__proto__ === Function.prototype.__proto__`3. `依据 Function.prototype.__proto__ === Object.prototype`4. `aaa.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype`
1. `aaa.__proto__.__proto__.__proto__`2. `aaa.__proto__.__proto__.__proto__ === Object.prototype.__proto__`3. `依据 Object.prototype.__proto__ === null`4. `aaa.__proto__.__proto__.__proto__ === null`
还是上面代码,我们接着推导_aaa.proto.proto.proto
1. `_aaa.__proto__`2. `_aaa的构造函数是 aaa`3. `_aaa.constructor === aaa`4. `_aaa.__proto__ === _aaa.constructor.prototype`5. `_aaa.__proto__ === aaa.prototype`
1. `_aaa.__proto__.__proto__`2. `_aaa.__proto__.__proto__ === aaa.prototype.__proto__`3. `参考图,Foo.prototype.__proto__ === Object.prototype`4. `_aaa.__proto__.__proto__ === aaa.prototype.__proto__ === Object.protype`
1. `_aaa.__proto__.__proto__.__proto__`2. `_aaa.__proto__.__proto__.__proto__ === Object.protype.__proto__`3. `依据 Object.prototype.__proto__ === null`4. `_aaa.__proto__.__proto__ === null`
正文延伸, 加上继承关系
我们再来看看,带继承关系的
1. `function aaa(){}function bbb(){}`2. `bbb.prototype = new aaa()var _bbb = new bbb();`3. `bbb.__proto__.__proto__.__proto__ === null`
这个没啥好说, 关键来看看 bbb.prototype.proto.proto.proto1.
1. `bbb.prototype.__proto__`2. `bbb.prototype.__proto__ === bbb.prototype.constructor.prototype`3. `bbb.prototype的原型是 aaa的实例, bbb原型的构造函数就是aaa,所以`4. `bbb.prototype.__proto__ === aaa.prototype`
1. `bbb.prototype.__proto__.__proto__`2. `bbb.prototype.__proto__.__proto__ === aaa.prototype.__proto__`3. `参考图,Foo.prototype.__proto__ === Object.prototype`4. `bbb.prototype.__proto__.__proto__ === Object.prototype`
1. `bbb.prototype.__proto__.__proto__`2. `bbb.prototype.__proto__.__proto__ .__proto__=== Object.prototype.__proto__ === null`
再来看看_bbb.proto.proto.proto .proto、
1. `1._bbb.__proto__`2. `_bbb.__proto__ === bbb.prototype`
1. `2._bbb.proto.proto`2. `_bbb.__proto__.__proto__ === bbb.prototype._proto__ === bbb.prototype.constructor.prototype === aaa.prototype`
1. `3._bbb.proto.proto.proto`2. `_bbb.__proto__.__proto__.__proto__ === aaa.prototype.__proto__`3. `参考图Foo.prototype.__proto__ === Object.prototype`4. `_bbb.__proto__.__proto__.__proto__ === aaa.prototype.__proto__ === Object.prototype`
1. `4._bbb.__proto__.__proto__.__proto__.__proto__`2. `_bbb.__proto__.__proto__.__proto__.__proto__ === Object.prototype.__proto__ === null`
正文 再加量
看看如下代码
1. `function aaa(){}var _aaa = new aaa()`2. `function bbb(){}`3. `bbb.prototype = new aaa();`4. `var _bbb = new bbb();`5. `function ccc(){}`6. `ccc.prototype = new bbb()var _ccc = new ccc()`
我们再来分析_ccc的prototype和proto,你们会说,你有完没完,那我就不分析了,我来推断:推断:
任何自定义的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
1. `js ccc.__proto__.__proto__.__proto__ === null // true`
继承关系的function fn,假设继承次数为n,
1. `_fn = new fn();`
那么
1. `_fn.__protot__[3+ n] === null`
_ccc应该是3+2就是5次
1. `js _ccc.__proto__.__proto__.__proto__.__proto__.__proto__ === null// true`
继承关系的function fn,假设继承次数为n
推到 fn.prototype.proto[3+n-1] ccc应该是 4次protojs ccc.prototype.proto.proto.proto.proto === null // true 当然上面关联的关系,就自己慢慢看吧
正文之外, class
下面的代码也是遵守规则,至于为什么,问自己喽
1. `class aaa {}`2. `class bbb extends aaa{}`3. `class ccc extends bbb{};`4. `var _ccc = new ccc()`
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()
比如,
1. `var a ={}, b = newObject(), c = [];`2. `a.__proto__ === a.constructor.prototype === Object.protype`3. `a.__proto__.__proto__ === Object.protype.__proto__ === null`4. `8.基本数据类型string,number,boolean,比如 var a = '', b=10, c= false,`5. `b.__proto__ === b.constructor.prototype === Number.prototype`6. `b.__proto__.__proto__ === Number.prototype.__proto__ === Object.prototype`7. `b.__proto__.__proto__.__proto__ === Object.prototype.__proto__ === null`8. `9.null和undefined没有__proto__`
最终
1.看图 2.浏览器输入 xx.proto 或者xx.prototype自己看去