親愛的開發(fā)者們,今天我們來聊聊JavaScript中不可或缺的原型鏈。它不僅是實現(xiàn)函數(shù)和對象繼承的基石,更是JavaScript這門語言靈活性和動態(tài)性的體現(xiàn)。理解原型鏈,就像是掌握了一扇窗,透過它,你可以看到函數(shù)、對象以及它們之間關(guān)系的本質(zhì)。在接下來的日子里,讓我們一起探索原型鏈的奧秘,掌握這門語言的精髓。
JavaScript,作為一門廣泛使用的編程語言,其核心特性之一就是原型鏈,在JavaScript中,所有函數(shù)的原型都是Function.prototype
,而所有對象的原型鏈最終都會指向Object.prototype
,這一機制是JavaScript實現(xiàn)繼承和原型模式的基礎(chǔ)。
讓我們深入探討Foo
的原型。Foo
是一個函數(shù),其構(gòu)造函數(shù)是JavaScript內(nèi)部的Function()
,由于Function
的prototype
屬性指向了一個對象Function.prototype
,因此Foo
的__proto__
屬性也就指向了Function.prototype
,這種關(guān)系可以用圖示來直觀地展示。
對于函數(shù)而言,prototype
屬性是其獨有的,以Person
為例,Person.prototype
是一個對象,它包含兩個屬性:constructor
指向其構(gòu)造函數(shù)Person
,以及__proto__
屬性,這個屬性是一個對象,指向上一層的原型。
函數(shù)對象對應(yīng)的類型是Function
,這與數(shù)組對象對應(yīng)的類型是Array
相似,當(dāng)我們使用new Fn()
創(chuàng)建一個對象時,實際上就是在調(diào)用構(gòu)造函數(shù)。
JavaScript的原型和原型鏈具有以下特點:
- 原型鏈實現(xiàn)了繼承,在JavaScript中,每個函數(shù)都有一個prototype
屬性,默認(rèn)情況下,所有函數(shù)的prototype
都是Object
的實例。
- 每個繼承父函數(shù)的子函數(shù)的對象都包含一個內(nèi)部屬性proto
,這個屬性指向父函數(shù)的原型。
原型鏈的具體實現(xiàn)如下:
- 在創(chuàng)建對象時,構(gòu)造函數(shù)內(nèi)部定義一般成員,而成員函數(shù)則定義在原型上。
- JavaScript中有兩個特殊的對象:Object
與Function
,它們都是構(gòu)造函數(shù),用于生成對象。
每個JavaScript對象內(nèi)部都有一個指向其他對象的“指針”或“引用”,通過這種方式在對象之間建立了一種鏈?zhǔn)浇Y(jié)構(gòu),這就是所謂的原型鏈。
在討論原型鏈之前,我們先來區(qū)分一下“原型”和“原形”這兩個詞。
1、意義和用法不同:“原型”通常指的是某一個事物或設(shè)計的最初構(gòu)思,也可以表示某個抽象概念的原始形態(tài)或最早的雛形。
2、區(qū)別:
- 原型是事物的所指;
- 原形是指事物的本身;
- 原型是指原來的類型或模型,特指文學(xué)藝術(shù)作品中塑造人物形象所依據(jù)的現(xiàn)實生活中的人;
- 原形本來的形狀,原來的形態(tài),本來的狀態(tài)。
3、具體解釋:
- 原型:原始的模型,特指文學(xué)藝術(shù)作品中塑造人物形象所依據(jù)的現(xiàn)實生活中的人。
- 原形:指事物本來的樣子,孫悟空變成個老太太,那老太太的原形就是孫悟空,它們其實是同一個事物,原型指一個事物的來源的依據(jù),這個事物和原型有某種共性,但不是同一個事物。
在JavaScript中,由于沒有類的概念,繼承通常是通過原型鏈來實現(xiàn)的,以下是兩種繼承方式的比較:
1、原型鏈繼承:
- 優(yōu)點:從instanceof
關(guān)鍵字來看,實例既是父類的實例,又是子類的實例,看起來似乎是最純粹的繼承。
- 構(gòu)造函數(shù)、原型和實例的關(guān)系:每個構(gòu)造函數(shù)都有一個原型對象,原型對象包含一個指向構(gòu)造函數(shù)的指針,而實例包含一個指向原型對象的內(nèi)部指針。
- 原型鏈基本思想:利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。
2、優(yōu)點與缺點:
- 優(yōu)點:實現(xiàn)簡單,易于理解。
- 缺點:在創(chuàng)建實例時,無法向構(gòu)造函數(shù)傳遞參數(shù),且原型上的方法會被所有實例共享,可能會導(dǎo)致數(shù)據(jù)污染。
JavaScript中沒有類的概念,只有函數(shù)和原型,這種設(shè)計主要受到了Self(一種基于原型的編程語言)和Scheme(一門函數(shù)式編程語言)的影響,JavaScript的這種能力主要來自于原型。
原型設(shè)計是交互設(shè)計師與產(chǎn)品經(jīng)理、項目經(jīng)理、網(wǎng)站開發(fā)工程師溝通的最好工具,在產(chǎn)品設(shè)計過程中,原型設(shè)計是一個至關(guān)重要的步驟,它是對一個產(chǎn)品的可視化呈現(xiàn),主要傳達產(chǎn)品的信息架構(gòu)、內(nèi)容、功能和交互方式。
1、原型設(shè)計的作用:
- 是交互設(shè)計師與團隊成員溝通的橋梁;
- 是產(chǎn)品設(shè)計初期供團隊參考、討論、評估的主要依據(jù)。
2、前端與后臺原型設(shè)計:
- 前端的原型設(shè)計主要包括產(chǎn)品展示、支付界面、訂單購物車界面、圖文資訊界面、用戶個人中心界面等;
- 后臺原型設(shè)計主要包括用戶管理界面、產(chǎn)品管理界面、訂單管理界面、圖文管理界面、操作員管理界面等。
3、原型圖設(shè)計:
- 是設(shè)計過程中使用的一種技術(shù),通常在設(shè)計的早期階段使用;
- 是一個代表了設(shè)計概念的可視化模型,允許團隊成員對設(shè)計的可行性進行討論和反饋。
4、原型設(shè)計的類型:
- 紙質(zhì)原型和電子原型;
- 方便設(shè)計師或設(shè)計團隊之間溝通、協(xié)作和迭代產(chǎn)品設(shè)計構(gòu)思。
通過原型設(shè)計,設(shè)計師可以更好地理解用戶需求,優(yōu)化產(chǎn)品設(shè)計,確保產(chǎn)品在開發(fā)過程中能夠順利實施。
在JavaScript中,constructor
屬性指向構(gòu)造函數(shù),構(gòu)造函數(shù)又通過prototype
屬性指回原型,并不是所有函數(shù)都具有這個屬性,例如Function.prototype.bind()
就沒有這個屬性。
原型鏈的基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法,每個構(gòu)造函數(shù)都有一個原型對象,原型對象包含一個指向構(gòu)造函數(shù)的指針,而實例包含一個指向原型對象的指針。
為了創(chuàng)建實例,需要組合使用構(gòu)造函數(shù)模式和原型模式,在構(gòu)造函數(shù)中定義實例的屬性,而共享的方法則定義在原型對象中,在子構(gòu)造函數(shù)中調(diào)用父構(gòu)造函數(shù)的call(this, name)
實現(xiàn)構(gòu)造函數(shù)之間的屬性繼承。
原型對象也可以層層繼承,而沒有繼承任何對象的最頂層對象(如{}
)的constructor
就是Object
這個原生超級根對象構(gòu)造器。
基于原型鏈的繼承中,JavaScript對象是動態(tài)的屬性“包”,具有指向一個原型對象的鏈,在給子類型原型添加方法時,如果父類上也有同樣的名字,子類型將會覆蓋這個方法,達到重新的目的,但這個方法依然存在于父類中。