JS面試題之詳解prototype、__proto__、constructor

前言

關於原型鏈的問題一直都有,雖然每次需要用到的時候能快速回顧和掌握,但也難免會遺漏一兩個重點,顧特寫此博客,記錄知識也分享知識!

相關知識點

知識點一:__proto__和constructor屬性是對象所獨有的,prototype屬性是函數所獨有的,但函數同時也是一種對象。
知識點二:通過構造函數創建的對象的原型指向構造函數的prototype屬性。
知識點三:只有.prototype對象才實際擁有constructor屬性,其他對象都是通過原型鏈,即__proto__屬性間接獲得(null也算一種數據類型,這裏不算對象)
知識點四:new操作符調用構造函數時經歷的過程

  • 1.創建一個對象
  • 2.將構造函數的作用域賦給新對象,此時this指向新對象
  • 3.執行構造函數中的代碼,爲新對象添加屬性
  • 4.返回對象
    (知識點四此次說得不太完整,詳細請點擊閱讀JS面試題之詳解new操作符)
    知識點五:Object是最頂層對象,Object的原型對象Object.prototype爲null
    知識點六:Function()是最頂層函數,Function()的constructor屬性爲Function()本身

以上知識點可能一開始看有點懵,但是不重要,接下來都會重點講解,看到最後再回頭來看這裏,肯定會感覺豁然開朗。

開始講解

相信很多人一直聽到原型鏈,但是具體又說不清楚是什麼,說不清楚__proto__和prototype之間的關係,其實所有的數據都放在prototype屬性中,__proto__是用來連接prototype屬性的,也就是所謂的鏈。
現在正式開始! 讓我們從如下一個簡單的例子展開討論,並配以相關的圖幫助理解:
我們先從最簡單的例子開始討論

function Foo() {...};
let f1 = new Foo();

雖然是簡簡單單的兩行代碼,它們背後的關係如下圖所示:
在這裏插入圖片描述
說明:
圖的最左邊即爲例子代碼;
圖的中間部分即爲它們之間的聯繫;
右下角爲圖例,
紅色箭頭表示__proto__屬性指向、
綠色箭頭表示prototype屬性的指向、
棕色實線箭頭表示本身具有的constructor屬性的指向,
棕色虛線箭頭表示繼承而來的constructor屬性的指向;
藍色方塊表示對象,淺綠色方塊表示函數(同時也是對象)。
你可能看不懂這張圖,但是沒關係,上面都是一些總結性的內容,以下開始分點講解。

1.proto

下圖爲只有__proto__屬性的關係圖
在這裏插入圖片描述
回顧知識點二,五,六
第一,這裏我們僅留下 proto 屬性,它是對象所獨有的,可以看到__proto__屬性都是由一個對象指向一個對象,即指向它們的構造函數的prototype原型對象,__proto__屬性的作用就是當訪問一個對象的屬性時,
理解方式一:如果該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象(可以理解爲父對象)裏找,如果父對象也不存在這個屬性,則繼續往父對象的__proto__屬性所指向的那個對象(可以理解爲爺爺對象)裏找,如果還沒找到,則繼續往上找…直到原型鏈頂端null(可以理解爲原始人。。。),再往上找就相當於在null上取值,會報錯(可以理解爲,再往上就已經不是“人”的範疇了,找不到了,到此結束,null爲原型鏈的終點),
理解方式二:可以從代理的方式理解,如果該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象裏找(可以理解爲上級代理,相當於自己沒貨,去上級代理那裏拿貨),如果上級代理也不存在這個屬性,則繼續往上級代理的__proto__屬性所指向的那個對象裏找(可以理解爲上上級代理,相當於上級代理也沒貨,它得去上上級代理那裏拿貨),如果還沒找到,則繼續往上找…直到原型鏈頂端null(可以理解爲廠家,如果廠家都沒貨,那就爲null,就會報錯,到此結束,null爲原型鏈的終點),
由以上這種通過__proto__屬性來連接對象直到null的一條鏈即爲我們所謂的原型鏈。(__proto__只起連接作用,數據都存在prototype屬性裏面)
  其實我們平時調用的字符串方法、數組方法、對象方法、函數方法等都是靠__proto__繼承而來的。之後會專門一篇講解slice-splice-split-join-substr-substring-slice方法的文章和一篇講解bind-call-apply方法的文章。

2.prototype屬性

接下來我們看 prototype 屬性:
在這裏插入圖片描述
回顧知識點一,prototype屬性,它是函數所獨有的,它是從一個函數指向一個對象。它的含義是函數的原型對象,也就是這個函數(其實所有函數都可以作爲構造函數)所創建的實例的原型對象,由此可知:f1.proto === Foo.prototype,它們兩個完全一樣。prototype屬性的作用就是讓該函數所實例化的對象們都可以找到公用的共享的屬性和方法。任何函數在創建的時候,其實會默認同時創建該函數的prototype對象。

3.constructor屬性

在這裏插入圖片描述
constructor屬性也是對象才擁有的,它是從一個對象指向一個函數,含義就是指向該對象的構造函數,每個對象都有直接或者間接的構造函數(本身擁有或繼承而來,繼承而來的要結合__proto__屬性查看會更清楚點,如下圖所示),從上圖中可以看出Function這個對象比較特殊,它的構造函數就是它自己(因爲Function可以看成是一個函數,也可以是一個對象),所有函數和對象最終都是由Function構造函數得來,所以constructor屬性的終點就是Function這個函數。
在這裏插入圖片描述

在這裏插入圖片描述

最後

希望這篇博客對大家能有所幫助,如果對你有所幫助,麻煩點贊支持一下,謝謝!
此文爲參考 原文 而寫,爲感謝原文作者的付出,特出附上原文連接

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