淺析JS中的原型,原型鏈和繼承
經(jīng)典模式和圣杯模式區(qū)別
經(jīng)典模式和圣杯模式都是用于解決構(gòu)造函數(shù)繼承和原型繼承的問題,但它們?cè)趯?shí)現(xiàn)繼承的方式上有所不同。
經(jīng)典模式是通過將子類的原型對(duì)象設(shè)置為父類的實(shí)例來實(shí)現(xiàn)繼承,然后將子類的構(gòu)造函數(shù)設(shè)置為子類本身。這樣子類既可以繼承父類的屬性,也可以繼承父類原型對(duì)象的方法。但是經(jīng)典模式存在一個(gè)問題,就是每次創(chuàng)建子類的實(shí)例時(shí)都會(huì)調(diào)用一次父類的構(gòu)造函數(shù),導(dǎo)致父類的屬性被重復(fù)初始化。
圣杯模式是在經(jīng)典模式的基礎(chǔ)上進(jìn)行了改進(jìn),通過使用一個(gè)中間函數(shù)來實(shí)現(xiàn)繼承。這個(gè)中間函數(shù)將父類的原型對(duì)象賦值給一個(gè)臨時(shí)的構(gòu)造函數(shù),并將子類的原型對(duì)象設(shè)置為這個(gè)臨時(shí)構(gòu)造函數(shù)的實(shí)例。這樣子類既可以繼承父類原型對(duì)象的方法,又不會(huì)重復(fù)調(diào)用父類的構(gòu)造函數(shù)。此外,圣杯模式還通過將子類的原型對(duì)象的constructor屬性設(shè)置為子類本身來修復(fù)原型鏈斷裂的問題。
下面是經(jīng)典模式和圣杯模式的代碼示例:
經(jīng)典模式:
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function Child(name) { Parent.call(this, name); } Child.prototype = new Parent(); Child.prototype.constructor = Child;
圣杯模式:
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function inherit(C, P) { function F() {} F.prototype = P.prototype; C.prototype = new F(); C.prototype.constructor = C; } function Child(name) { Parent.call(this, name); } inherit(Child, Parent);
經(jīng)典模式和圣杯模式都是用于實(shí)現(xiàn)繼承的方式,但圣杯模式在解決經(jīng)典模式中的問題上更加優(yōu)化和完善。
圣杯模式
1. 原型
原型是JavaScript中用來實(shí)現(xiàn)對(duì)象之間繼承關(guān)系的概念。每個(gè)JavaScript對(duì)象都有一個(gè)原型對(duì)象,它是一個(gè)普通的對(duì)象,包含了對(duì)象的屬性和方法。當(dāng)我們?cè)L問一個(gè)對(duì)象的屬性或方法時(shí),如果對(duì)象本身不存在該屬性或方法,JavaScript會(huì)自動(dòng)去原型對(duì)象中查找。
2. 原型鏈
原型鏈?zhǔn)且环N通過原型對(duì)象來實(shí)現(xiàn)對(duì)象之間繼承關(guān)系的機(jī)制。每個(gè)對(duì)象都有一個(gè)原型對(duì)象,通過原型鏈,一個(gè)對(duì)象可以訪問其原型對(duì)象的屬性和方法。原型鏈?zhǔn)怯梢幌盗性蛯?duì)象組成的,當(dāng)我們?cè)L問一個(gè)對(duì)象的屬性或方法時(shí),JavaScript會(huì)自動(dòng)沿著原型鏈向上查找,直到找到該屬性或方法或者到達(dá)原型鏈的頂端。
3. 繼承
繼承是一種面向?qū)ο缶幊讨械闹匾拍?,它允許我們創(chuàng)建一個(gè)新的對(duì)象,并從一個(gè)已有的對(duì)象中繼承屬性和方法。通過繼承,我們可以避免重復(fù)編寫相同的代碼,提高代碼的復(fù)用性和可維護(hù)性。
相應(yīng)的代碼示例
a. 原型鏈繼承
原型鏈繼承是一種簡(jiǎn)單的繼承方式,它通過將子類的原型對(duì)象設(shè)置為父類的實(shí)例來實(shí)現(xiàn)繼承。這樣子類就可以訪問父類原型對(duì)象的屬性和方法。
function Parent() { this.name = 'Parent'; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function Child() { this.name = 'Child'; } Child.prototype = new Parent(); var child = new Child(); child.sayHello(); // 輸出: Hello, I am Child
在這個(gè)例子中,我們定義了一個(gè)父類Parent和一個(gè)子類Child。在子類中,我們將其原型對(duì)象設(shè)置為父類的實(shí)例,這樣子類就可以繼承父類的屬性和方法。在子類的實(shí)例中,我們可以調(diào)用父類原型對(duì)象的方法。
b. 構(gòu)造函數(shù)繼承
構(gòu)造函數(shù)繼承是一種通過調(diào)用父類的構(gòu)造函數(shù)來實(shí)現(xiàn)繼承的方式。子類通過調(diào)用父類的構(gòu)造函數(shù)來繼承父類的屬性,并在子類的構(gòu)造函數(shù)中使用call方法來調(diào)用父類的構(gòu)造函數(shù)。
function Parent(name) { this.name = name; } function Child(name) { Parent.call(this, name); } var child = new Child('Child'); console.log(child.name); // 輸出: Child
在這個(gè)例子中,我們定義了一個(gè)父類Parent和一個(gè)子類Child。在子類的構(gòu)造函數(shù)中,我們使用call方法調(diào)用父類的構(gòu)造函數(shù),并將子類的實(shí)例作為this參數(shù)傳遞給父類的構(gòu)造函數(shù)。這樣子類就可以繼承父類的屬性。
c. 組合繼承
組合繼承是一種通過同時(shí)使用原型鏈繼承和構(gòu)造函數(shù)繼承來實(shí)現(xiàn)繼承的方式。它通過將子類的原型對(duì)象設(shè)置為父類的實(shí)例,并在子類的構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù)來實(shí)現(xiàn)繼承。
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function Child(name) { Parent.call(this, name); } Child.prototype = new Parent(); Child.prototype.constructor = Child; var child = new Child('Child'); child.sayHello(); // 輸出: Hello, I am Child
在這個(gè)例子中,我們定義了一個(gè)父類Parent和一個(gè)子類Child。在子類的構(gòu)造函數(shù)中,我們使用call方法調(diào)用父類的構(gòu)造函數(shù),并將子類的實(shí)例作為this參數(shù)傳遞給父類的構(gòu)造函數(shù)。然后,我們將子類的原型對(duì)象設(shè)置為父類的實(shí)例,并將子類的構(gòu)造函數(shù)設(shè)置為子類本身。這樣子類既可以繼承父類的屬性,也可以繼承父類原型對(duì)象的方法。
詳細(xì)代碼說明
a. 原型鏈繼承
function Parent() { this.name = 'Parent'; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function Child() { this.name = 'Child'; } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; var child = new Child(); child.sayHello(); // 輸出: Hello, I am Child
在這個(gè)例子中,我們使用Object.create()方法將子類的原型對(duì)象設(shè)置為父類的原型對(duì)象的一個(gè)副本。這樣子類就可以繼承父類原型對(duì)象的屬性和方法。
b. 構(gòu)造函數(shù)繼承
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function Child(name) { Parent.call(this, name); } var child = new Child('Child'); child.sayHello(); // 輸出: TypeError: child.sayHello is not a function
在這個(gè)例子中,我們通過調(diào)用父類的構(gòu)造函數(shù)來繼承父類的屬性,但是子類無法繼承父類原型對(duì)象的方法。
c. 組合繼承
在這個(gè)例子中,我們使用Object.create()方法將子類的原型對(duì)象設(shè)置為父類的原型對(duì)象的一個(gè)副本,并將子類的構(gòu)造函數(shù)設(shè)置為子類本身。這樣子類既可以繼承父類的屬性,也可以繼承父類原型對(duì)象的方法。
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log('Hello, I am ' + this.name); } function Child(name) { Parent.call(this, name); } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; var child = new Child('Child'); child.sayHello(); // 輸出: Hello, I am Child
到此這篇關(guān)于淺析JS中的原型,原型鏈和繼承的文章就介紹到這了,更多相關(guān)JS原型 原型鏈 繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript中with()方法的語(yǔ)法格式及使用
有了 With 語(yǔ)句,在存取對(duì)象屬性和方法時(shí)就不用重復(fù)指定參考對(duì)象,下面為大家介紹下With 語(yǔ)句的語(yǔ)法格式及使用2014-08-08unicloud云開發(fā)進(jìn)階獲取首頁(yè)列表數(shù)據(jù)示例詳解
這篇文章主要為大家介紹了unicloud云開發(fā)進(jìn)階獲取首頁(yè)列表數(shù)據(jù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03微信小程序swiper左右擴(kuò)展各顯示一半代碼實(shí)例
這篇文章主要介紹了微信小程序swiper左右擴(kuò)展各顯示一半代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12javascript內(nèi)存分配原理實(shí)例分析
這篇文章主要介紹了javascript內(nèi)存分配原理,結(jié)合實(shí)例形式分析了javascript原始值和引用值內(nèi)存分配的原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-04-04Js實(shí)現(xiàn)中國(guó)公民身份證號(hào)碼有效性驗(yàn)證實(shí)例代碼
這篇文章主要介紹了Js實(shí)現(xiàn)中國(guó)公民身份證號(hào)碼有效性驗(yàn)證實(shí)例代碼,可以識(shí)別身份證號(hào)碼的正確性,有興趣的可以了解一下2017-05-05js中方法重載如何實(shí)現(xiàn)?以及函數(shù)的參數(shù)問題
js中沒有辦法直接實(shí)現(xiàn)方法重載,但每一個(gè)函數(shù)都有一個(gè)特殊的參數(shù)arguments,利用它可以實(shí)現(xiàn)方法的重載,具體示例如下2013-08-08