徹底深刻理解js原型鏈之prototype,__proto__以及constructor(二)

前言

如果你能夠啃下教程一併且喫透原型鏈的幾個概念的話說明你在前端飛仙的路上又進了一小步···學習最怕的不是慢而是站!這篇教程主要目的對原型鏈概念進一步加深理解

鞏固下教程一的知識

來看下面的例子:

var text=new String("我是文字");
function Persion(name,job){
    this.name=name;
    this.job=job;
}
Persion.myName="lxm";
Persion.prototype.sayName=function(){
    alert(this.name);
}
var perison1=new Persion("lxm","20")

思考:判斷下列表達式返回的值:

(兩分鐘之內對八道的算及格,剩下的同學回頭接着理解教程一,傳送門在此 [http://0313.name/2017/01/13/prototype-proto-constructor.html])

perison1.__proto__===Persion.prototype;
perison1.name===Persion.name;
perison1.prototype.__proto__===Object.prototype;
Persion.prototype.__proto__===Object.prototype;
Persion.__proto__===Function.prototype;
Persion.constructor===perison1;
Function.__proto__===Object.prototype;
Function.prototype.__proto__===Object.prototype;
typeof Persion.prototype;
typeof Function.prototype;

原型鏈圖

這個圖絕對是網絡上獨一無二獨一份,此乃小米飛昇教程獨家祕籍!因爲博主在學習過程中發現對文字的理解和記憶遠遠不如一個圖來的更深更直觀,更加透徹,爲了您更好的學習原型鏈,博主特意花了一上午的時間用mermaid繪製了這個原型鏈的關係圖,而且通過這個圖我們能夠發現很多有意思的事情
爲了關係圖更加直觀和清晰,隱去了一些引用線路,其中:

  • 圓形代表對象的名字
  • 方形代表屬性名
  • 實線代表對象的分界
  • 虛線代表引用
  • 菱形代表基本值

git

  1. 原型鏈是單鏈,只往一個方向流向,沒有迴路

  2. 只有Function的__proto__指向自己的prototype,這也向我們解釋了爲什麼Function.prototype類型是function

  3. 我們通過__proto__只能獲取到原型對象中的方法和屬性,所以persion1通過原型鏈是獲取不到Persion的myName屬性,但是我們可以通過原型對象的constructor來獲取或者修改Persion的屬性(這點太給力了)

請注意,有時候這個方法也不好使,因爲原型對象的constructor是可以改變的,不一定指向原型對象所在的函數對象

繼續上面的例子:

persion1.__proto__.constructor.myName="我變了耶!";
console.log(Persion.myName); //我變了耶
  1. 普通對象的_proto__一定指向創造它的函數對象的prototype
  2. 原型對象的__proto__一定指向Object.prototype!
  3. 通過圖我們可以簡單理解,擁有原型對象屬性的對象是函數對象,否則爲普通對象
  4. 原型鏈是有開始和盡頭的,開始於null,結束於普通對象
  5. 所有的函數對象都是Function以new的方式創造出來了,包括Function自己且每個函數對象的__proto__都指向了Function.prototype
  6. Object是所有對象的父類,我們也可以稱之爲基類,不過不要糾結於叫什麼,因爲我們通過圖可以看到每一個對象(不管是原型對象還是普通對象還是函數對象)的通過原型鏈都可以引向Object.prototype

** 以上九條我稱爲原型鏈之九句真言(不要太在意名字,我自己隨便起的 ~) **

意外收穫:this.name和this.job難道不應該在Persion中也有一份嗎?無數個日夜,愚笨的博主對this的用法都不甚瞭解,直到我畫出了這種圖,我tm徹底明白了this的含義,就是誰運行包含this的這個函數,this就把掛在它身上的包袱(屬性)甩給誰!
看到了嗎,persion1調用了Persion,那麼自然多了2個屬性,但是注意,name跟job並不是Persion的屬性!!

思考:圖中沒有畫出Object.__proto__的指向,請問他指向哪?(請只依據九句真言解答)

思考題解答

思考:判斷下列表達式返回的值:

perison1.__proto__===Persion.prototype;

首先判斷perison1是通過new方式被Persion創造出來的,依據九句真言第4條得出 :true

perison1.name===Persion.name;

通過關係圖可以看到不相等,我已經在意外收穫中解答了,答案爲:false

perison1.prototype.__proto__===Object.prototype;

只看圖可以看到perison1沒有prototype,是普通對象所以答案爲:js報錯~~

Persion.prototype.__proto__===Object.prototype;

參考九句真言第5條:答案爲:true

Persion.__proto__===Function.prototype;

Persion爲函數對象,參考九句真言第8條,答案爲:true

Persion.constructor===perison1;

Persion是由Function創造出來的所以Persion.constructor指向Function,答案爲:false

Function.__proto__===Object.prototype;

Function我們已經反覆強調是由自身創造所以Function.proto===Function.prototype;,答案爲:false

Function.prototype.__proto__===Object.prototype;

根據九句真言第5條,答案爲:true

typeof Persion.prototype;

答案爲:object

typeof Function.prototype;

答案爲:function,注意這個是比較特殊的原型對象

思考:圖中沒有畫出Object.__proto__的指向,請問他指向哪?(請只依據九句真言解答)

下面來分步解答

  1. Object屬於函數對象
  2. 依據九句真言第八條得出函數對象的__proto__都指向了Function.prototype
  3. 所以Object.proto===Function.prototype

這一點是不太好理解的,是Function創造了Object,然後Object創造了Function的原型對象prototype
所以就有了

Object.__proto__===Function.prototype
Function.prototype.__proto__===Object.prototype

不要太糾結於此,只要理解就好

結束語

好了,原型鏈的概念原理通過這2篇教程我相信大家已經滾瓜爛熟了!下面的教程,我們會着重研究下原型鏈在實際的應用!

作者:宜信技術學院 劉曉敏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章