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

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

一:對象的分類

  • JS中對象分為兩種,函數對象普通對象。也稱為Function Object和Object。通過typeof 可以查看具體的對象類型。
  • JS中的函數對象,在和new結合的時候,可以創(chuàng)建新的對象。JS提供了兩個最基本的函數對象 FunctionObject。其他所有的對象都由這兩個函數對象演進而來
  • JS中的函數對象,有兩個方法可以創(chuàng)建,一個是通過new Function(),一個是通過function() {}聲明。
  • JS中的普通對象,也有兩個方法可以創(chuàng)建,一個是通過 new (非Function函數對象/**Object**) ,一個是通過 { }等各類語法聲明。Array也可視為一個普通對象,可以通過new Array(),也可以通過[]
  • 另外,還有一個特殊的Object.create()方法,可以由一個普通對象創(chuàng)建一個新的普通對象。此時第一個普通對象起到類似函數對象的作用,不同之處在于,新建對象的__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的特性,都指向創(chuàng)建該對象的函數對象的prototype屬性。即
(普通對象).__proto__ == (創(chuàng)建它的函數對象).prototype
(函數對象).__proto__ == Function.prototype  // 函數對象都由 new Function()創(chuàng)建

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

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: 當函數執(zhí)行時這個 this 指的是誰?
}
var person1 = new person('Mick');
person1.getName(); //Mick
person1.name; //Mick
person1.toString(); // [object Object]
  • 當person1執(zhí)行getName方法的時候,先在person1的自身屬性中尋找。此時自有屬性只有name屬性,未找到,則繼續(xù)在person1的__proto__屬性中尋找
  • 因為person1.__proto__ = Person.prototype。此時在Person.prototype中尋找getName屬性,此時尋找得到,將Person.prototype.getName返回作為person1.getName,進行執(zhí)行。
  • 當person1執(zhí)行toString方法的時候,在Person.prototype中未能找到,則繼續(xù)在Person.prototype.__proto__中尋找。
  • Person.prototype作為Person的一個特殊實例,它是普通對象。普通對象都由new Object創(chuàng)建。因此Person.prototype.__proto__ = Object.prototype。因此繼續(xù)在Object.prototype中尋找,發(fā)現了toString方法,將Object.prototype.toString返回作為person1.toString,進行執(zhí)行。
  • 需要注意,JS中的原型鏈繼承,指的是新建對象和創(chuàng)建函數對象的prototype之間的關系,而不是和創(chuàng)建函數的關系。能夠在原型鏈繼承上傳遞下去的只有原型對象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)創(chuàng)建它的函數對象的prototype上的屬性(2)函數對象繼承自其它函數對象prototype上的屬性(3)Object函數對象的prototype上的屬性
  • 所有的函數對象,都會繼承(1)Function.prototype上的屬性(2)Object函數對象的prototype上的屬性
  • 最后所有的對象的原型鏈都會追溯到null標識符上

六:Function和Object自帶屬性

參考鏈接

http://www.itdecent.cn/p/dee9f8b14771
http://www.itdecent.cn/p/652991a67186
http://www.itdecent.cn/p/a4e1e7b6f4f8

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容