淺析JS中的原型,原型鏈和繼承
經(jīng)典模式和圣杯模式區(qū)別
經(jīng)典模式和圣杯模式都是用于解決構(gòu)造函數(shù)繼承和原型繼承的問題,但它們在實(shí)現(xiàn)繼承的方式上有所不同。
經(jīng)典模式是通過將子類的原型對象設(shè)置為父類的實(shí)例來實(shí)現(xiàn)繼承,然后將子類的構(gòu)造函數(shù)設(shè)置為子類本身。這樣子類既可以繼承父類的屬性,也可以繼承父類原型對象的方法。但是經(jīng)典模式存在一個問題,就是每次創(chuàng)建子類的實(shí)例時都會調(diào)用一次父類的構(gòu)造函數(shù),導(dǎo)致父類的屬性被重復(fù)初始化。
圣杯模式是在經(jīng)典模式的基礎(chǔ)上進(jìn)行了改進(jìn),通過使用一個中間函數(shù)來實(shí)現(xiàn)繼承。這個中間函數(shù)將父類的原型對象賦值給一個臨時的構(gòu)造函數(shù),并將子類的原型對象設(shè)置為這個臨時構(gòu)造函數(shù)的實(shí)例。這樣子類既可以繼承父類原型對象的方法,又不會重復(fù)調(diào)用父類的構(gòu)造函數(shù)。此外,圣杯模式還通過將子類的原型對象的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)對象之間繼承關(guān)系的概念。每個JavaScript對象都有一個原型對象,它是一個普通的對象,包含了對象的屬性和方法。當(dāng)我們訪問一個對象的屬性或方法時,如果對象本身不存在該屬性或方法,JavaScript會自動去原型對象中查找。
2. 原型鏈
原型鏈?zhǔn)且环N通過原型對象來實(shí)現(xiàn)對象之間繼承關(guān)系的機(jī)制。每個對象都有一個原型對象,通過原型鏈,一個對象可以訪問其原型對象的屬性和方法。原型鏈?zhǔn)怯梢幌盗性蛯ο蠼M成的,當(dāng)我們訪問一個對象的屬性或方法時,JavaScript會自動沿著原型鏈向上查找,直到找到該屬性或方法或者到達(dá)原型鏈的頂端。
3. 繼承
繼承是一種面向?qū)ο缶幊讨械闹匾拍?,它允許我們創(chuàng)建一個新的對象,并從一個已有的對象中繼承屬性和方法。通過繼承,我們可以避免重復(fù)編寫相同的代碼,提高代碼的復(fù)用性和可維護(hù)性。
相應(yīng)的代碼示例
a. 原型鏈繼承
原型鏈繼承是一種簡單的繼承方式,它通過將子類的原型對象設(shè)置為父類的實(shí)例來實(shí)現(xiàn)繼承。這樣子類就可以訪問父類原型對象的屬性和方法。
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在這個例子中,我們定義了一個父類Parent和一個子類Child。在子類中,我們將其原型對象設(shè)置為父類的實(shí)例,這樣子類就可以繼承父類的屬性和方法。在子類的實(shí)例中,我們可以調(diào)用父類原型對象的方法。
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在這個例子中,我們定義了一個父類Parent和一個子類Child。在子類的構(gòu)造函數(shù)中,我們使用call方法調(diào)用父類的構(gòu)造函數(shù),并將子類的實(shí)例作為this參數(shù)傳遞給父類的構(gòu)造函數(shù)。這樣子類就可以繼承父類的屬性。
c. 組合繼承
組合繼承是一種通過同時使用原型鏈繼承和構(gòu)造函數(shù)繼承來實(shí)現(xiàn)繼承的方式。它通過將子類的原型對象設(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在這個例子中,我們定義了一個父類Parent和一個子類Child。在子類的構(gòu)造函數(shù)中,我們使用call方法調(diào)用父類的構(gòu)造函數(shù),并將子類的實(shí)例作為this參數(shù)傳遞給父類的構(gòu)造函數(shù)。然后,我們將子類的原型對象設(shè)置為父類的實(shí)例,并將子類的構(gòu)造函數(shù)設(shè)置為子類本身。這樣子類既可以繼承父類的屬性,也可以繼承父類原型對象的方法。
詳細(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在這個例子中,我們使用Object.create()方法將子類的原型對象設(shè)置為父類的原型對象的一個副本。這樣子類就可以繼承父類原型對象的屬性和方法。
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在這個例子中,我們通過調(diào)用父類的構(gòu)造函數(shù)來繼承父類的屬性,但是子類無法繼承父類原型對象的方法。
c. 組合繼承
在這個例子中,我們使用Object.create()方法將子類的原型對象設(shè)置為父類的原型對象的一個副本,并將子類的構(gòu)造函數(shù)設(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);
}
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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
快速學(xué)習(xí)JavaScript的6個思維技巧
在這篇文章中,我將介紹六個思維技巧來幫助你更快地學(xué)習(xí)JavaScript,并成為一個更快樂、更富有成效的程序員。2015-10-10
uni-app使用uploadFile上傳多張圖片的具體實(shí)現(xiàn)
在微信小程序中不支持多張圖片上傳,需要做循環(huán)實(shí)現(xiàn)多張圖片上傳,下面這篇文章主要給大家介紹了關(guān)于uni-app使用uploadFile上傳多張圖片的具體實(shí)現(xiàn),需要的朋友可以參考下2023-04-04
基于Bootstrap使用jQuery實(shí)現(xiàn)輸入框組input-group的添加與刪除
這篇文章主要介紹了基于Bootstrap使用jQuery實(shí)現(xiàn)輸入框組input-group的添加與刪除的相關(guān)資料,需要的朋友可以參考下2016-05-05
基于BootstrapValidator的Form表單驗(yàn)證(24)
這篇文章主要為大家詳細(xì)介紹了基于BootstrapValidator的Form表驗(yàn)證,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
js實(shí)現(xiàn)感應(yīng)鼠標(biāo)圖片透明度變化的方法
這篇文章主要介紹了js實(shí)現(xiàn)感應(yīng)鼠標(biāo)圖片透明度變化的方法,涉及javascript鼠標(biāo)操作及css修改技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-02-02
JavaScript刪除數(shù)組中指定元素5種方法例子
這篇文章主要給大家介紹了關(guān)于JavaScript刪除數(shù)組中指定元素5種方法,在最近的項(xiàng)目中,有用到j(luò)s對數(shù)組的操作,所以這里總結(jié)一下,需要的朋友可以參考下2023-07-07
uniapp組件傳值的方法(父傳子,子傳父,對象傳值)實(shí)戰(zhàn)案例
現(xiàn)在的前端開發(fā)中基本上都是組件化開發(fā)的,下面這篇文章主要給大家介紹了關(guān)于uniapp組件傳值(父傳子,子傳父,對象傳值)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03

