js原型鏈看這篇就夠了


談到js原型大家會想到什么,是不是會發出這樣的感嘆,我明明好好的去看了啊,為什么我還是不懂,我真是太難了,知識裝不進腦子啊,本人其實一開始也是這個樣子,看了許多關於解釋原型,原型鏈的帖子,什么原型的栗子,什么造物者上帝啊巴拉巴拉,但是還是雲里霧里,好像懂了,好像不懂,經過本人這段時間對原型的仔細研究,終於能通過理解畫出原型鏈的死亡之圖了,放圖

死亡之圖???,是的,因為當時自以為原型鏈嘛我懂了,簡單(牛皮吹到天上去了),再看這張圖,我emmmm什么都沒看懂,瞬間打臉,所以本人形象的稱他為原型鏈之死亡之圖🙃🙃🙃

准備好了嗎,我要開始畫圖了(ps:我可是沒有死記硬背哦,本人也想死記硬背,但是這知識進不了腦子啊,所以一般知識點都靠理解,我這腦子都能懂,你們也可以的😀)

第一部分 構造函數 && 原型對象

function Animal(name,age) {
    this.name = name
    this.age = age
}

let pig = new Animal('peiqi',3)
console.log(pig)

我們看上面的例子,我們創建了一個大寫的Animal()函數,並且里面定義了一些屬性,然后new了一個Animal,並且把它賦值給了pig,像這個大寫的函數Animal就是一個構造函數,它可以通過new創建它的實例對象,其中pig就是Animal的實例對象,當然你還可以new其他的實例對象比如說bird,dog等等,每個構造函數都有一個prototype屬性,我們稱之為顯式原型對象,每個實例對象都有一個proto屬性,我們稱之為隱式原型對象,他們都是指向同一個原型對象(敲黑板!!!)

微信圖片_20200316151047.png

我們可以看到,紅框中的內容是一摸一樣的,

上面的代碼就相當於這個樣子,現在聽我解釋:

  1. 函數其實是個對象,但是這個對象是可以加()運行的,而普通的對象,比如說{a:1},是不可以加括號來執行的,我們把可以執行的對象稱之為函數對象
  2. 對象,函數,這種我們都知道,他是個引用類型,引用類型在內存中是從棧中獲取該對象的內存地址,然后再從堆內存中取得所需要的數據
    image.png
  3. 上面的圖,Animal是個函數,他在棧上存了一個叫Animal的變量對應的是堆上的一個函數對象,他在堆上內存地址為0x111(就是棧上存了一個堆上的地址),Animal是一個構造函數,所以他有一個prototype的屬性(就是顯式原型對象),這個屬性是一個普通的對象,因此他也需要在堆上在開辟一個新的內存存prototype對象,存的地址為0x222,而他在Animal函數對象上,只存了prototype對象的地址
  4. pig是通過Animal構造函數new出來的一個實例對象,他在棧上也存了一個叫做pig的變量,對應的是堆上的一個函數對象,他在堆上的內存地址為0x333,實例對象身上都有一個__proto__屬性(隱式原型對象),他也是一個對象,並且構造函數的顯式原型對象 === 實例對象的隱式原型對象 所以__proto__ 指向0x222

第二部分 原型鏈到哪結束

image.png
從上圖來看,我們可以清晰的看到,_ proto _ 只到Object就沒有了,通過下圖,我們來捋一遍Object與其他構造函數之間的關系
image.png

  1. 任何的對象都是new Object()出來的
  2. Object()也是一個構造函數,所以他在棧上存了一個Object的變量,對應的是堆上的函數對象,這個對象在堆上的內存地址是0x444,並且里面還裝了一個prototype屬性(構造函數身上必有一個prototype屬性),他在堆內存中也開了一塊地址,去存他的prototype,內存地址為0x555
  3. 原型對象(不管是顯式原型對象還是隱式原型對象)都是普通對象,他不能加()運行,他相當於是通過new Object()產生的,所以所有的普通對象都有一個__proto__屬性,並且普通對象._ proto _=== Object.prototype
  4. Animal的顯式原型對象也是普通對象,所以他的顯式原型對象中有一個__proto__屬性,它指向Object的顯式原型對象

你可能會問那Object的顯式原型對象不是也是對象嗎,他身上不是應該也有個__proto__屬性,指向Object的顯式原型對象,但是這個樣子就會出現死循環,沒有出口出去,所以Object.prototype._ proto _= null

第三部分 function Animal() 與 function Function()

我們知道不管是什么函數,都是相當於 new Function(),所以普通的構造函數Animal() 和 Function()之間存在着聯系,我們看下圖
image.png

構造函數Animal相當於 new Function()出來的,所以此時Animal()是Function()的實例對象,之前說過只要是實例對象,必定存在__proto__屬性,所以Animal._ proto _ 指向Function()的顯式原型對象,即 Animal._ proto _ === Function.prototype

第四部分 function Function() && Object.prototype 關系大亂燉(這是原型鏈中最難理解的一部分)

image.png

  1. function Object()也是個函數,所以我們可以認為Object()是通過 new Function() 出來的,所以Object()此時是實例對象,實例對象上面一定有__proto__屬性,所以Object._ proto _ === Function.prototype
  2. function Function()同樣也是函數,我們也可以認為他是通過 new Function() 出來的,所以Function()此時是實例對象,實例對象上面一定有__proto__屬性,所以Function._ proto _ === Function.prototype
  3. 我們說過任何東西都是new Object()所出來的,所以Function() 也是new Object() 出來的,此時Function()是實例對象,實例對象上面一定有__proto__屬性,但是Function的__proto__屬性的連線已經連到了Function的顯式原型對象,所以它通過上圖的紅線進行連接,Function._ proto . proto _=== Object.prototype

結束 && 總結

通過這么幾張圖,其實我們已經把那張死亡之圖畫完了(把我畫的那幾張圖都連起來就ok了),不信你們可以比較一下我們自己畫的圖和那張圖,只是表現形式有所不同,我們只要理解以下幾點:

  1. 函數也是對象,跟普通函數相比,它可以加()運行
  2. 構造函數身上一定能有prototype屬性
  3. 實例對象身上一定有__proto__屬性
  4. function Object() 和 function Functiton() 也是函數可以通過 new Function() 創建
  5. function Function() 是函數對象,他也是對象,所以可以通過 new Object() 創建

如果能理解以上的幾點,畫出死亡之圖真的很輕松哦✌✌✌

結束語

好啦,我把我如何理解的畫原型鏈的圖告訴你們了,可以自己動手畫一下,如果有什么問題或者錯誤可以私信我哦🤞🤞🤞


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM