最詳盡的 JS 原型與原型鏈終極詳解記錄

該文章來自于最詳盡的 JS 原型與原型鏈終極詳解,沒有「可能是」的學習總結

一:對象的分類

  • JS中對象分為兩種,函數對象普通對象。也稱為Function Object和Object。通過typeof 可以查看具體的對象類型。
  • JS中的函數對象,在和new結合的時候,可以創建新的對象。JS提供了兩個最基本的函數對象 FunctionObject。其他所有的對象都由這兩個函數對象演進而來
  • JS中的函數對象,有兩個方法可以創建,一個是通過new Function(),一個是通過function() {}聲明。
  • JS中的普通對象,也有兩個方法可以創建,一個是通過 new (非Function函數對象/**Object**) ,一個是通過 { }等各類語法聲明。Array也可視為一個普通對象,可以通過new Array(),也可以通過[]
  • 另外,還有一個特殊的Object.create()方法,可以由一個普通對象創建一個新的普通對象。此時第一個普通對象起到類似函數對象的作用,不同之處在于,新建對象的__proto__指向第二個普通對象自身。因為普通函數沒有prototype屬性(這個可以看完下面的回頭再理解下)。
var o1 = {}; 
var o2 =new Object();
var o3 = new f1();
var o4 = Object.create(o2)

function f1(){}; 
var f2 = function(){};
var f3 = new Function('str','console.log(str)');

console.log(typeof Object); //function 
console.log(typeof Function); //function  

console.log(typeof f1); //function 
console.log(typeof f2); //function 
console.log(typeof f3); //function   

console.log(typeof o1); //object 
console.log(typeof o2); //object 
console.log(typeof o3); //object
console.log(typeof o4); //object

二:prototype 和 __proto__

  • JS中的任意一個對象都包括一個 __proto__屬性。該屬性在ES2015之前,并沒有在標準中明確定義,而是一個大多數瀏覽器默認支持的一個屬性,也稱為[[prototype]]
  • JS中的任意一個函數對象都包括了一個prototype屬性。該屬性相當于是當前函數對象的一個特殊實例。一般為普通對象。
  • JS中任意一個對象的__proto__屬性,根據new的特性,都指向創建該對象的函數對象的prototype屬性。即
(普通對象).__proto__ == (創建它的函數對象).prototype
(函數對象).__proto__ == Function.prototype  // 函數對象都由 new Function()創建

FunctionObject都是函數對象,都是通過new Function()創建,所以

Function.__proto__ == Function.prototype
Object.__proto__ == Function.prototype
  • JS中的函數對象的prototype一般都為普通對象即
typeof A.prototype == 'Object'  // A

Function除外,因為Function的新建實例還是一個函數對象,所以

typeof Function.prototype == 'function'

但是該prototype是一個特殊的函數對象。它沒有prototype,另外,它的__proto__指向了Object.prototype,而不是Function的prototype,即

typeof Function.prototype == 'function'
Function.prototype.__proto__ == Object.prototype
  • JS中的所有函數對象的prototype都有一個constructor函數,稱為構建函數,該構建函數指向當前函數對象。即
function f1() {}
f1.prototype.constructor == f1
Function.prototype.constructor == Function
  • prototype,__proto__以及constructor的關系圖


    image.png

    其中的person1.constructor其實是通過原型鏈繼承在Person.prototype中尋得。

三:原型鏈繼承

JS中的原生繼承是通過原型鏈完成的。以下面的代碼為例子

var Person = function(name){
  this.name = name; 
};
Person.prototype.getName = function(){
  return this.name;  // tip: 當函數執行時這個 this 指的是誰?
}
var person1 = new person('Mick');
person1.getName(); //Mick
person1.name; //Mick
person1.toString(); // [object Object]
  • 當person1執行getName方法的時候,先在person1的自身屬性中尋找。此時自有屬性只有name屬性,未找到,則繼續在person1的__proto__屬性中尋找
  • 因為person1.__proto__ = Person.prototype。此時在Person.prototype中尋找getName屬性,此時尋找得到,將Person.prototype.getName返回作為person1.getName,進行執行。
  • 當person1執行toString方法的時候,在Person.prototype中未能找到,則繼續在Person.prototype.__proto__中尋找。
  • Person.prototype作為Person的一個特殊實例,它是普通對象。普通對象都由new Object創建。因此Person.prototype.__proto__ = Object.prototype。因此繼續在Object.prototype中尋找,發現了toString方法,將Object.prototype.toString返回作為person1.toString,進行執行。
  • 需要注意,JS中的原型鏈繼承,指的是新建對象和創建函數對象的prototype之間的關系,而不是和創建函數的關系。能夠在原型鏈繼承上傳遞下去的只有原型對象prototype上的函數。比如Object擁有geOwnPropertyNames方法,但Object.prototype卻不包含,所以person1也無法擁有getOwnPropertyNames 方法。同樣的,如果新建一個函數對象Student,讓它繼承Person函數對象,那么new Stuednet()新建的對象也只能繼承Person.prototype.getName,而不能繼承person.name屬性

四:JS中原型鏈繼承鏈路

  • Function函數對象
Function.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
Object.prototype.__proto__ == null
  • Object函數對象
Object.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
Object.prototype.__proto__ == null
  • 自定義函數對象
function f1() {}
f1.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
Object.prototype.__proto__ == null
  • 自定義函數對象實例--也是普通對象
function f1() {}
o1 = new f1()
o1.__proto__ = f1.prototype
f1.prototype__proto__ == Object.prototype
Object.prototype.__proto__ == null
  • 自定義函數對象繼承--繼承自某一個自定義對象
function f1() {}
function f2() {} // 設定f2繼承自f1,具體如何實現繼承,可以查看另一篇文章
o2 = new f2()
o2.__proto__ = f2.prototype
f2.prototype.__proto__ = f1.prototype
f1.prototype__proto__ == Object.prototype
Object.prototype.__proto__ == null

五:總結

  • 所有的普通對象,都會繼承(1)創建它的函數對象的prototype上的屬性(2)函數對象繼承自其它函數對象prototype上的屬性(3)Object函數對象的prototype上的屬性
  • 所有的函數對象,都會繼承(1)Function.prototype上的屬性(2)Object函數對象的prototype上的屬性
  • 最后所有的對象的原型鏈都會追溯到null標識符上

六:Function和Object自帶屬性

參考鏈接

http://www.lxweimin.com/p/dee9f8b14771
http://www.lxweimin.com/p/652991a67186
http://www.lxweimin.com/p/a4e1e7b6f4f8

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容