一文教你深入淺出__proto__和prototype的區(qū)別和聯(lián)系
前話
有一個(gè)很喜歡裝逼的同事,寫了一段代碼
1. ?`function a(){}`
2. ?`a.__proto__.__proto__.__proto__`
然后問我,下面這個(gè)玩意a.proto.proto.proto是啥,然后我一臉懵逼,prototype還知道一點(diǎn),這個(gè)proto,還來三個(gè),是個(gè)什么鬼。于是我一直不能放下這個(gè)問題,雖然我很懶,很不喜歡費(fèi)腦子,但是這個(gè)坎還是過不去,最近兩天研究了大半天,就有了這篇文章。
我先說出答案, 上面的值為 null。我還很負(fù)責(zé)的告訴你,下面的_a.proto.proto.proto也是null
1. ?`function a(){}var _a = new a();`2. ?`_a.__proto__.__proto__.__proto__`
先來一張非常經(jīng)典的圖,真的是非常經(jīng)典,你看懂他,你就懂了整個(gè)世界,然后整個(gè)世界就等著你去拯救整個(gè)世界。)

正文之前, proto_和prototype
都誰有的問題
typeof === object的有proto?, null和undefined都沒有 typeof === function的有proto和prototype
proto?是什么?
proto?一般情況指向的是該對(duì)象的構(gòu)造函數(shù)的prototype,一般情況,因?yàn)檫€有很二般的情況。先來看個(gè)簡單的例子, 下面的輸出是true
1. ?`function a(){}var _a = new a()console.log(_a.__proto__ === a.prototype)`
那我問_a.proto.proto為什么呢,你會(huì)這么推導(dǎo)么,
依據(jù)上面a.proto?=== a.prototype,那么a.proto.proto就等同a.prototype.proto?, 那么我們就再推到等于 a.prototype.constructor.prototype,然后你去一比,結(jié)果是false。_a.proto.proto=== a.prototype.constructor.prototype // false
幾條規(guī)則
這個(gè)先不糾結(jié), 我們先看看上圖,我們先得知道或者記住這幾個(gè)規(guī)則
一.Object.prototype.proto?=== null
不要糾結(jié),鐵律
二.Object.proto?=== Function.prototype
Object,Number, Error等等這些函數(shù)都是Function創(chuàng)建的,下面就說明 這些的constructor就是Function,這里比較有意思的就是 Function.constructor也是Function。那就有Object.proto?=== Function.prototype === Function.protoObject.constructor.prototype === Function.prototype // trueFunction.constructor === Function// true
Function.prototype.proto?=== Object.prototype 這個(gè)就是這樣的設(shè)計(jì), Function.prototype.constructor === Object // false
自定義函數(shù),沒有修改默認(rèn)原型的情況下,比如 function Person(){}, Person.prototype.proto?=== Object.prototype Person.constructor === Function 對(duì)比3一看,F(xiàn)unction和構(gòu)造函數(shù)是Function的Person,他們prototype.proto的指向是一樣的。
進(jìn)入正題
有這幾個(gè)基本東西,我們就可以來推導(dǎo)了。
先看下面的代碼,
1. ?`js 我們來推到 aaa.__proto__.__proto__.__proto__`2. ?`function aaa(){} var _aaa = new aaa()`
1. ?`aaa.__proto__`2. ?`aaa構(gòu)造函數(shù)是Function`3. ?`aaa.constructor === Function`4. ?`aaa.__proto__ === Function.prototype`
1. ?`aaa.__proto__.__proto__`2. ?`aaa.__proto__.__proto__ === Function.prototype.__proto__`3. ?`依據(jù) 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. ?`依據(jù) Object.prototype.__proto__ === null`4. ?`aaa.__proto__.__proto__.__proto__ === null`
還是上面代碼,我們接著推導(dǎo)_aaa.proto.proto.proto
1. ?`_aaa.__proto__`2. ?`_aaa的構(gòu)造函數(shù)是 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. ?`參考圖,F(xiàn)oo.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. ?`依據(jù) Object.prototype.__proto__ === null`4. ?`_aaa.__proto__.__proto__ === null`
正文延伸, 加上繼承關(guān)系
我們?cè)賮砜纯?,帶繼承關(guān)系的
1. ?`function aaa(){}function bbb(){}`2. ?`bbb.prototype = new aaa()var _bbb = new bbb();`3. ?`bbb.__proto__.__proto__.__proto__ === null`
這個(gè)沒啥好說, 關(guān)鍵來看看 bbb.prototype.proto.proto.proto1.
1. ?`bbb.prototype.__proto__`2. ?`bbb.prototype.__proto__ === bbb.prototype.constructor.prototype`3. ?`bbb.prototype的原型是 aaa的實(shí)例, bbb原型的構(gòu)造函數(shù)就是aaa,所以`4. ?`bbb.prototype.__proto__ === aaa.prototype`
1. ?`bbb.prototype.__proto__.__proto__`2. ?`bbb.prototype.__proto__.__proto__ === aaa.prototype.__proto__`3. ?`參考圖,F(xiàn)oo.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()`
我們?cè)賮矸治鯻ccc的prototype和proto,你們會(huì)說,你有完沒完,那我就不分析了,我來推斷:推斷:
任何自定義的function本身,三次proto必然是null,也就是往上找三代
包括Function,Object, Error等等 Fucntion.proto?看圖,依據(jù)
Object.proto?=== Function.prototype === Function.proto我們來推導(dǎo)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構(gòu)造出來的
我們來測(cè)試一下ccc
1. ?`js ccc.__proto__.__proto__.__proto__ === ?null ?// true`
繼承關(guān)系的function fn,假設(shè)繼承次數(shù)為n,
1. ?`_fn = new fn();`
那么
1. ?`_fn.__protot__[3+ n] === null`
_ccc應(yīng)該是3+2就是5次
1. ?`js _ccc.__proto__.__proto__.__proto__.__proto__.__proto__ === null// true`
繼承關(guān)系的function fn,假設(shè)繼承次數(shù)為n
推到 fn.prototype.proto[3+n-1] ccc應(yīng)該是 4次protojs ccc.prototype.proto.proto.proto.proto?=== null // true 當(dāng)然上面關(guān)聯(lián)的關(guān)系,就自己慢慢看吧
正文之外, class
下面的代碼也是遵守規(guī)則,至于為什么,問自己嘍
1. ?`class aaa {}`2. ?`class bbb extends aaa{}`3. ?`class ccc extends bbb{};`4. ?`var _ccc = ?new ccc()`
1.proto因?yàn)檫@些都是Function創(chuàng)建出來的函數(shù),proto在函數(shù)上時(shí)就是表示構(gòu)造函數(shù)的prototype,所以 .proto?=== .constrcutor.prototype === Function.prototype
2..prototype.proto?這些老骨頭不遵循?proto?為構(gòu)造函數(shù)的prototype 在上面提到過了,F(xiàn)unction.prototype.proto?=== Object.prototype, 類推,這些內(nèi)置的老骨頭的 .prototype.proto?=== Object.prototype
總結(jié)
總結(jié), 特別需要記憶的:
1.Object.prototype.proto?=== null
2.Function.prototype.proto?=== Object.prototype 內(nèi)置Number,Boolen, String,Function, Date, Array, RegExp等一樣
3.Object.proto?=== Function.prototype === Function.proto聯(lián)系2,這些東西都是Function創(chuàng)建出來的
4.Math, JSON的ptoto是 Object.prototype typeof 可以看出來這兩個(gè)是object,而不是Function 5.function a(){} 這樣創(chuàng)建出來,沒有繼承關(guān)系的函數(shù) a.prototype.proto?=== Object.prototype 6.有繼承關(guān)系的function看上面的推斷 7.對(duì)象字面量和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.基本數(shù)據(jù)類型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自己看去