JS中的原型鏈詳解
JS雖然不是物件導向類型的語言,但這不並不代表JS就不能夠實現OOP的特性。 我相信大家在使用JS的時候,一定有用過Object的原型方法,像是call,apply,hasOwnProperty等等方法,可是這些方法是從哪裡來的呢?如果JS無法實作繼承的話,這些方法的使用就無從談起了。這裡我們就來談談在JS實現繼承的方法,原型鏈。
_proto_和prototype
首先我們要了解什麼是普通對象,什麼是函數物件。
普通物件
#var a = {}
#var a = new Object();
var a = new f1();//與上一個建立物件的方式相同
函數物件
var a = function(){};
var a = new Function() {};
f1()
#_proto_是每個普通物件都擁有的屬性,用來指向建構函數的prototype,也就是建構函式的原型物件。而建構子的原型物件一般來說也是一個普通物件(在建構子是Function的時候,它就變成了一個函數物件),所以它也有_proto_屬性。而它的_proto_則指向它的建構子的原型對象,也就是Object.prototype。最後的Object.prototype._proto_指向null,到了原型鏈的頂端。
prototype是函數物件都擁有的屬性,它在物件建立的時候被指定給新的物件實例。當然也可以動態修改。
function Person(){}; var p = new Person();//创建一个普通对象 //创建过程实际为 var p={}; p._proto_=Person.prototype; Person.apply(p,arguments);//或者是call... //执行构造函数,并返回创建的对象。
對上面程式碼的補充說明
正常來講建構函式中是不用寫return語句的,因為它會預設回傳新建立的物件。但是,如果在建構函式中寫了return語句,如果return的是一個對象,那麼函數就會覆寫新建立的對象,而傳回此物件;如果return的是基本型別如字串、數字、布林值等,那麼函數會忽略掉return語句,還是傳回新建立的物件。
而建構函數的原型物件的預設值為:
Person.prototype={ constructor://指向构造函数本身 _proto_://指向构造函数Person的原型对象的构造函数的原型对象,这里是指Object.prototype } //这里有一个特殊情况——当构造函数为Function的时候 Function.prototype._proto_===Object.prototype //我们知道Function.prototype是一个函数对象,它的_proto_应该指向它的构造函数的原型,也就是Function.prototype。 //可是这样下去就没完没了了,毕竟一条链总是有顶端的。这里约定Function.prototype._proto_===Object.prototype; //这时,Object.prototype._proto_===null;完美结束原型链。
我們可以不斷修改建構子的原型物件的指向,這樣最終就可以形成一條鏈。而上面提到的一條鏈就是JS中的預設原型鏈。
談談程式碼實作
下面我們來看看程式碼:
function Parent(name){ this.name=name||"parent"; } function Son(name){ this.name=name||"son"; this.property="initial Son name"; } function Grandson(name){ this.name=name||"grandson"; this.ggs="initial Grandson name"; } Son.prototype = new Parent("原型中的Parent"); Grandson.prototype = new Son("原型中的Son"); let grandson = new Grandson("孙子"); console.log(grandson instanceof Son);//true console.log(grandson instanceof Grandson);//true console.log(grandson instanceof Parent);//true
很顯然,最後都會輸出true。但是我們改動一點程式碼:
Grandson.prototype = new Son("原型中的Son"); Son.prototype = new Parent("原型中的Parent");//其实上一步已经实例化了一个Son的对象给Grandson.prototype //这个时候Son的实例的_proto_已经确定指向那个时候的构造函数.prototype了(默认原型对象) let grandson = new Grandson("孙子"); console.log(grandson instanceof Son);//false console.log(grandson instanceof Grandson);//true console.log(grandson instanceof Parent);//false
為什麼結果會改變呢?原因也很簡單。我們之前有提到物件的創建的創建過程:物件在實例化的時候就已經給物件的_proto_賦了建構子的prototype了。也就是說上面程式碼中第一行已經確定了Grandson.prototype._proto_的值了,即使在第二行修改了Son.prototype也是無法修改Grandson.prototype._proto_的值。
Conclusion:JS中原型鏈的關係是由_proto_維持的,而不是prototype。
小測驗
var animal = function(){}; var dog = function(){}; animal.price = 2000; dog.prototype = animal; var tidy = new dog(); console.log(dog.price) console.log(tidy.price)
答案是輸出什麼呢?是undefined和2000,我們分析一下:
首先我們清楚animal和dog都是函數對象,在第四行修改了dog的原型對象為animal。那我們接著往下看,console.log(dog.price)
這句話首先會尋找dog的price,沒有。然後到原型鏈上尋找。怎麼找的呢?我們之前提到是透過_proto_去到它建構函數的原型物件上,這裡因為dog是函數對象,那麼它的建構函式的原型物件就是Function.prototype,這是一個empty function。於是回傳undefined,沒有找到price這個屬性。
那麼console.log(tidy.price)
呢?
tidy是一個普通對象,首先也是尋找它本身的屬性price,也沒有。透過_proto_去到它建構函式的原型物件上,也就是dog.prototype。因為tidy實例化在dog.prototype = animal;
之後,所以tidy._proto_的指向已經指向了修改後的dog.prototype。也就是指向了animal,也就是能夠找到price這個屬性了,所以輸出2000。
原型物件上的所有屬性和方法都可以看成是Java中父類別的public(protected)屬性和方法,在這些方法內部使用this即可存取建構函式中的屬性和方法。至於為什麼,這又得提到JS中this的綁定問題了….總而言之,誰調用的函數,this就指向誰。箭頭函數除外…
相關建議:
以上是JS中的原型鏈詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Windows作業系統是全球最受歡迎的作業系統之一,其新版本Win11備受矚目。在Win11系統中,管理員權限的取得是一個重要的操作,管理員權限可以讓使用者對系統進行更多的操作和設定。本文將詳細介紹在Win11系統中如何取得管理員權限,以及如何有效地管理權限。在Win11系統中,管理員權限分為本機管理員和網域管理員兩種。本機管理員是指具有對本機電腦的完全管理權限

OracleSQL中的除法運算詳解在OracleSQL中,除法運算是一種常見且重要的數學運算運算,用來計算兩個數相除的結果。除法在資料庫查詢中經常用到,因此了解OracleSQL中的除法運算及其用法是資料庫開發人員必備的技能之一。本文將詳細討論OracleSQL中除法運算的相關知識,並提供具體的程式碼範例供讀者參考。一、OracleSQL中的除法運算

Linux系統呼叫system()函數詳解系統呼叫是Linux作業系統中非常重要的一部分,它提供了一種與系統核心互動的方式。其中,system()函數是常用的系統呼叫函數之一。本文將詳細介紹system()函數的使用方法,並提供對應的程式碼範例。系統呼叫的基本概念系統呼叫是使用者程式與作業系統核心互動的一種方式。使用者程式透過呼叫系統呼叫函數來請求作業系統

PHP中的模運算子(%)是用來取得兩個數值相除的餘數的。在本文中,我們將詳細討論模運算子的作用及用法,並提供具體的程式碼範例來幫助讀者更好地理解。 1.模運算子的作用在數學中,當我們將一個整數除以另一個整數時,就會得到一個商和一個餘數。例如,當我們將10除以3時,商數為3,餘數為1。模運算子就是用來取得這個餘數的。 2.模運算子的用法在PHP中,使用%符號來表示模

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

Linux的curl命令詳解摘要:curl是一種強大的命令列工具,用於與伺服器進行資料通訊。本文將介紹curl指令的基本用法,並提供實際的程式碼範例,幫助讀者更好地理解和應用該指令。一、curl是什麼? curl是命令列工具,用於發送和接收各種網路請求。它支援多種協議,如HTTP、FTP、TELNET等,並提供了豐富的功能,如檔案上傳、檔案下載、資料傳輸、代

Promise.resolve()詳解,需要具體程式碼範例Promise是JavaScript中一種用來處理非同步操作的機制。在實際開發中,常常需要處理一些需要依序執行的非同步任務,而Promise.resolve()方法就是用來傳回一個已經Fulfilled狀態的Promise物件。 Promise.resolve()是Promise類別的靜態方法,它接受一個

Numpy是一款Python科學計算庫,提供了豐富的陣列操作函數與工具。升級Numpy版本時需要查詢目前版本以確保相容性,本文將詳細介紹Numpy版本查詢的方法,並提供具體的程式碼範例。方法一:使用Python程式碼查詢Numpy版本使用Python程式碼可以輕鬆查詢Numpy的版本,以下是實作方法和範例程式碼:importnumpyasnpprint(np
