您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“什么是JS原型和原型鏈”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
1.JS 的發(fā)展史
要想貫徹 JS 的核心設計思想,我們要從 JS 的誕生說起。
1.1 為什么會誕生 JavaScript ?
相對比較成熟的瀏覽器是由網(wǎng)景公司發(fā)布的,早些年間,瀏覽器只能瀏覽網(wǎng)頁內(nèi)容,而不能進行用戶交互。比如我們登錄輸入用戶名和密碼,在瀏覽器是不能進行判斷用戶是否真正輸入了,而是通過服務器來判斷,如果沒有輸入,返回錯誤提示用戶,這種設計非常的浪費時間和服務器資源。
為了解決這個問題,網(wǎng)景公司需要開發(fā)一種運行在瀏覽器中的腳本語言,用來簡單的做用戶輸入校驗等操作。
當時最流行的語言是面向?qū)ο蟮腏ava編程語言 ,網(wǎng)景公司為了能夠借助 Java將瀏覽器腳本語言流傳開,所以起名 JavaScript。其實兩者沒有任何的關(guān)系。
1.2 存在的問題
JS 中的數(shù)據(jù)類型設計受當時 Java流行的影響,都是對象類型,這時候就遇到問題了,有對象必然涉及到繼承機制,那么 JS 的繼承機制要設計成 Java一樣呢?還是另有設計思想?
2.JS 繼承的設計思想
JS 的開發(fā)者想如果設計成像 Java一樣有“類”的概念豈不是和 Java一樣成為了一種完全面向?qū)ο蟮木幊陶Z言了?最后決定自己設計一種繼承機制,但是它的設計思想還是采用了 Java的一些特性。
2.1 生成對象
通常 Java 生成對象是通過 new 的方式,通過類生成一個實例對象的過程。但是 JS 中并沒有類,那 JS 的設計者要怎么做?
他找到了 Java 和 JS 的共同點就是兩者都有構(gòu)造函數(shù), Java的 new 的過程內(nèi)部其實調(diào)用了構(gòu)造函數(shù)。但是 JS 是沒有“類”的概念的,于是 JS 就把new 一個“類”設計成了 new 一個構(gòu)造函數(shù),于是構(gòu)造函數(shù)成為了一個實例對象的原型對象。
3.為什么要設計原型對象?
上述這樣的原型設計有一個致命的缺點就是無法共享公共屬性。
因為我們知道,每 new 一個對象,生成的實例是兩個不同的對象。所以共有的屬性也不是共享的。
所以要設計一個對象專門用來存儲對象共享的屬性,那么我們叫它「原型對象」。
4.什么是原型對象?
要想讓構(gòu)造函數(shù)生成的所有實例對象都能夠共享屬性,那么我們就給構(gòu)造函數(shù)加一個屬性叫做prototype,用來指向原型對象,我們把所有實例對象共享的屬性和方法都放在這個構(gòu)造函數(shù)的prototype屬性指向的原型對象中,不需要共享的屬性和方法放在構(gòu)造函數(shù)中。
這里有一點疑惑就是,我們知道對象可以設置屬性,函數(shù)也可以設置屬性嗎?對于初學者來說是比較懵逼的,那我們可以稍微的簡單說一下:
JavaScript 中的函數(shù)擁有對象的所有能力,也因此可被稱作為任意其他類型對象來對待。當我們說函數(shù)是第一類對象的時候,就是說函數(shù)也能夠?qū)ο蟮囊恍┕δ?,比如添加屬性,函?shù)當做參數(shù)傳遞等。
所以說,實例對象一旦通過構(gòu)造函數(shù)創(chuàng)建,就會自動給實例對象賦值上原型對象上共享的屬性或方法。說清楚一點就是該對象屬性都指向了原型對象的屬性值。
5.對象和函數(shù)在原型鏈關(guān)系?
上述的圖反映了對象以及函數(shù)在原型鏈中的關(guān)系,如果你覺的上邊的這張圖看懵逼了,沒關(guān)系,我剛開始學習原型鏈的時候,根本不知道上邊這是什么“清明上河圖”,小鹿下面通過一步步的拆分講解,看這張圖就非常簡單,沒錯,非常簡單。
我們文章的開頭也說了什么是原型對象,說白了就是構(gòu)造函數(shù)的一個 prototype屬性,這個屬性就指向原型對象。
其實我們其中一些連接屬性沒有講到,只講到了prototype屬性,下面一張圖來將剩下的屬性補充完整,我們只要把這張圖印到大腦中就可以了。
我們來分析一下上圖,首先我們先要聲明一個狗的構(gòu)造函數(shù),定義其名字和體重屬性(私有屬性),同時每個構(gòu)造函數(shù)我們上邊講到了,都會有一個prototype屬性。
這個prototype指向的就是原型對象,原型對象放的就是對象共享的屬性。但是注意,原型對象里有一個constructor屬性,這個屬性又指回了構(gòu)造函數(shù)。
我們通過 new 構(gòu)造函數(shù)生成兩個狗的對象實例,一個叫豆豆,一個叫貝貝,這兩個是兩個不同的對象,名字體重都不相同,但是他們會共享原型對象上的屬性 type,它們共有的屬性都是犬類。
在 JS 所有對象中,只要是對象,都會有一個內(nèi)置屬性叫做_proto_,而且這個屬性是系統(tǒng)自動生成的,只要你創(chuàng)建一個對象,這個對象就有這個屬性。這個_proto_屬性指向的是原型對象。
通過上邊的分布講解,我們明白了構(gòu)造函數(shù)與對象實例以及原型對象的關(guān)系。
總結(jié)為一句話為:
構(gòu)造函數(shù)的 prototype 指向原型對象,原型對象有一個 constructor 屬性指回構(gòu)造函數(shù),每個構(gòu)造函數(shù)生成的實例對象都有一個 _proto_ 屬性,這個屬性指向原型對象。
沒錯,原型就是這么簡單。但是你會發(fā)現(xiàn),原型也是對象呀,你說只要是對象都會有一個_proto_屬性指向自身構(gòu)造函數(shù)的原型對象。
沒錯,要想知道原型對象的_proto_屬性指向誰,就要知道是哪個構(gòu)造函數(shù)創(chuàng)建了原型對象?
我們知道,所有的 JS 對象的都是繼承了一個叫做 Object 的對象??梢岳斫鉃镺bject 構(gòu)造函數(shù)創(chuàng)造了這個萬物,他們的關(guān)系如下,和上邊是同樣的道理,上邊總結(jié)的那句話好好理解一下。
但是上圖中會有一個疑問,Object 構(gòu)造函數(shù)原型對象的也是對象,它肯定也有一個_proto_屬性,為什么會指向 null 呢?
我們在拿上述總結(jié)的那句話,_proto_屬性指向的是自身構(gòu)造函數(shù)的原型對象,自身的構(gòu)造函數(shù)是誰?是 Object 構(gòu)造函數(shù),那 Object構(gòu)造函數(shù)的原型是誰?當然是本身(如圖),所以把_proto_指向了null。
上邊的關(guān)系如果不仔細整理的話確實很亂,尤其是對于初學者,但是如果像小鹿這樣已整理,再亂的關(guān)系把它安排的井井有條,沒有理解,就多看幾篇文章。
6.原型鏈
我們還有一個問題沒有解決就是原型鏈?既然我么你知道什么是原型了,原型鏈是什么?顧名思義,肯定是一條鏈,既然每個對象都有一個_proto_屬性指向原型對象,那么原型對象也有_proto_指向原型對象的原型對象,直到指向上圖中的null,這才到達原型鏈的頂端。
不要忘了,上邊那種圖我們還沒有把它理解,我們把圖自上而下理解。
第一張圖分解,上邊小鹿畫的圖的關(guān)系和這個一樣的,仔細對比一下,很簡單,第一張圖就這么解決了。
我們繼續(xù)向下分割,看第二張圖。
第二張圖怎么還是那么眼熟呢,這不是小鹿上邊分析的 Object 的關(guān)系圖嗎?對的,沒錯。
第三張圖,稍微繞個彎子,但是換湯不換藥呀,聽小鹿分析來。
看著還是眼熟,只不過把function換成了Function,f 變成了大寫的 F,這里涉及到一個知識點就是,在 JS 中,所有的 function函數(shù)都是由Function繼承來的,可以說是Function是所有 function的祖宗。
那Function是由誰生產(chǎn)來的?我們看到圖中的Function函數(shù)有_proto_屬性了,而且屬性指向自己的原型對象,那不就是自己繁衍自己嗎?可以這么理解。
“什么是JS原型和原型鏈”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。